I am plugging in Spring to existing Java EE web Application. I have following lines in my web.xml:
<listener>
<listener-class>com.MyContextListener</listener-class>
</listener>
And Following MyContextListener class?
public class MyContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
//...
}
}
What should I do to make MyContextListener be managed by Spring?
Edited:
My assumption is: Spring should create all servlets and all web app infrastructure so everything happened in contextInitialized method of MyContextListener should be somehow handled by Spring. How can I achieve, by implementing some interface I suppose. Correct me if I am wrong. Thanks!
Well,
We had a similar scenario of configuring an exiting Jersey web services app to use Spring for dependency injection. Our Jersey webapp had extended ContextLoaderListener as follow
public class XServletContextListener extends ContextLoaderListener {
...
#Override
public void contextInitialized(ServletContextEvent arg0) {
super.contextInitialized(arg0);
....
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
super.contextDestroyed(arg0);
....
}
}
where ContextLoaderListener is
import org.springframework.web.context.ContextLoaderListener;
We included the jersey-spring bridge with all spring dependencies including applicationContext.xml as follow
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.xxx.*" />
....
....
</beans>
And obviously needed to make sure that XServletContextListener is included in the web.xml as follow
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>com.xxx.**.XServletContextListener</listener-class>
</listener>
Followed by servlet and its init-param values and servlet mapping. You can obviously adopt annotation config in place of xml confib in which case you would need to use WebListener annotation.
We use a variety of annotations such as
#Component for objects
#Service for services
#Repository for DAOs
#Controller for controllers/resources
#ContextConfiguration for tests
Everything is loaded and autowired by Spring framework.
What should I do to make MyContextListener be managed by Spring?
It depends on which configuration way you are using. Anyway, you should tell directly Spring to use the class you have declared. That could be done by the following way:
#WebListener
public class MyContextListener implements ServletContextListener { ... }
A class marked with this annotation (the Servlet 3.0 specification, 8.1.4) must implement one of these interfaces
HttpSessionAttributeListener
HttpSessionListener
ServletContextAttributeListener
ServletContextListener (+)
ServletRequestAttributeListener
ServletRequestListener
HttpSessionIdListener
that it actually does.
Personally, I prefer a meta-annotation based approach which makes my configuration shorter and more concise.
Spring should create all servlets and all web app infrastructure so everything happened in contextInitialized method of MyContextListener should be somehow handled by Spring.
Yes, Spring will do it for you if you provide some information which could help it to register / configure / create / manage an instance.
The information may be either meta-information (a template that tells how to create an instance, like BeanDefinitions) or a completed instance itself (usually, it gets passed programmatically that, in turn, leads to writing a huge amount of code).
How can I achieve, by implementing some interface I suppose.
You are implementing an interface to make your listener a listener (a class that describes specific methods which will be called at some points of time). Spring, itself, is responsible for guaranteeing such calls at those points of time, placing an object in the existing web infrastructure before.
Either annotate the class with #WebListener or the method with #Bean
Annotate where you create a new instance of MyContextListener with #Bean if using Java Configs with Spring Boot.
Related
I am using Spring 4 (not Spring Boot) in the web application. I need to run some initialization code before any of the beans in the application context would be created. I tried to create implementation of org.springframework.context.ApplicationContextInitializer and register it in spring.factories but was not picked up for some reason. How can I do it?
As it turned out implementing of org.springframework.context.ApplicationContextInitializer was a right way. Because in my project I do not use Spring MVC implementation of this initializer should be registered in web.xml instead of spring.factories. Here is an example:
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>my.company.MyContextInitializer</param-value>
</context-param>
This should work. If not, please post your code.
#Component
public class SampleBootstrap implements ApplicationListener<ContextRefreshedEvent> {
....
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Do Something();
}
}
Having become very comfortable with dependency injection as a style, I've found myself writing an HTTP servlet something like this:
public class FooServlet extends HttpServlet {
private Dependency dependency;
public void setDependency(Dependency dependency) {
this.dependency = dependency;
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
...
Result r = dependency.doSomething(...);
...
}
This is beautifully easy to unit test, and I'm keen to keep the model -- but now that I come to deploy it in Tomcat, I come to realised that I don't know where I can invoke setDependency() from.
Some vague possibilities that come to mind:
Get servlet parameters in init(). These are just String, so I'd have to do some Reflection to create. This wouldn't be true DI; just configured dependency creation.
Something with JNDI
Somehow, from the Java program in which Tomcat is embedded, get Tomcat to give me a reference to the Servlet object, allowing me to call its setter.
Use Spring. If I use Spring, I'd be looking for ways to keep it lightweight. This app is not complex enough to warrant Spring MVC.
It's actually just two lines of code to make #Autowire work in a servlet:
ApplicationContext appContext = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() );
appContext.getAutowireCapableBeanFactory().autowireBean( this );
There is a drawback, though: Servlets are singletons and they aren't created by Spring, so you can't inject prototype beans. So this will work as long as all injected beans are singletons. When you add a prototype bean later, the code will start to fail with odd errors.
For this reason, I usually create handler beans (see HttpRequestHandler) and create them in doPost() instead of autowiring the servlet itself.
I'd use Spring, as it provides a large ecosystem of features and functionalities that could be used by your project to enhance it. But only if you'd really use them. There's no point in loading such a huge framework only to use one little feature in one single place.
That said, you should also take care as the doPost() method will be called by different threads, while your dependency object is a member variable. This would make your code thread-unsafe, as the same dependency instance could be simultaneously used by different threads if it were a singleton.
With thanks to Aaron and Filipe, I found what seems to be the most lightweight use of Spring.
Configure a Dispatching servlet in WEB-INF/web.xml:
<servlet>
<servlet-name>
myDispatcher
</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/myDispatcher-context.xml</param-value>
</init-param>
</servlet>
In WEB-INF/spring/myDispatcher-context.xml, configure the application context explicitly, so that BeanNameUrlHandlerMapping maps requests to your handling class, and your dependency is injected.
<bean id="/*" class="org.me.MyHandler">
<property name="dependency" ref="dependency"/>
</bean>
<bean id="dependency" class="org.me.myDependency"/>
Write MyHandler as an implementation of HttpRequestHandler - it's very much analogous to a Servlet.
This gives you dependency injection. It avoids classpath scanning, and does not load dozens of classes -- but if you want to adopt the more advanced Spring MVC features later, the opportunity is there.
I want to insert some data into the database using the application API if the application has started up with some empty database tables. How do I go about this?
I'm using Spring 3.1, Hibernate 4.1.1.
[edit]
Thanks to AlexR the answer is to sublcass ContextLoaderListener, call super in contextInitialized and then do whatever it is you need to do:
public class MyContextLoaderListener extends ContextLoaderListener {
public void contextInitialized(final ServletContextEvent event) {
super.contextInitialized(event);
// ... doStuff();
}
}
You may also need to wire this up in web.xml instead of the Spring one:
<listener>
<listener-class>com.example.MyContextLoaderListener</listener-class>
</listener>
You can use spring context listener.
Take a look on: http://fusesource.com/docs/framework/2.2/deploy_guide/CXFServletDeploySpring.html
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/context/ContextLoaderListener.html
http://forum.springsource.org/showthread.php?88896-Spring-MVC-3-is-ContextLoaderListener-needed
I have created a new Spring MVC 3 project using NetBean. But there is no option of adding a new controller in the IDE.
Well adding a Controller is as simple as adding a class annotated with
#Controller
And specifying the package to be scanned from applicationContext.xml which in turn is specified in the web.xml. Something like this:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/applicationContext.xml
</param-value>
</context-param>
in web.xml
Then in /WEB-INF/spring/appServlet/applicationContext.xml :
<context:component-scan base-package="your.package" />
Of course you need the actual schema in your applicationContext.xml
xmlns:context="http://www.springframework.org/schema/context"
And under schema location:
http://www.springframework.org/schema/context/spring-context-3.0.xsd
And then a class :
package your.package
.....
#Controller
MyController{
.....
If you are using an annotation driven implementation of Spring you don't need to do anything special. Create a standard Java class inside the package that Spring is configured to scan. Then annotate the class with #Controller then create your method(s) and mappings using #RequestMapping.
In its simplest form a controller would be something like:
#Controller
public class MyClass {
#RequestMapping("/myUrlMapping.do")
public ModelAndView myMethod() {
return new ModelAndView("myView");
}
}
This assumes you already have Spring configured correctly.
Is there any spring specific way in the framework to perform initialization when MVC loads up?
Say I need to create global objects based on configuration files, is there a place to do this or do I just create my own servlet and do this in oninit?
What about standard #PostConstruct?
#Service
class AnySpringBean {
#PostConstruct
public void init() {
//run when bean is created
}
}
Works on #Controllers as well.
UPDATE: The more global place would be to subclass ContextLoaderListener) and override contextInitialized() and use it in web.xml (see user1076371 answer). I don't like this approach much, but at least the initialization is not tied to any Spring bean.
There is an ApplicationListener interface you can implement to hook into the startup completion event. I use this in my app to do things after I know Spring has finished starting up. I have a few different classes that I want to kick off background threads after the system is "up" and each implements this interface to do their particular post startup stuff.
It's sent after the app as a whole is done, but it's each listening spring bean that gets an event, so you'd could hook it into some existing bean or to create something like a PostStartupBean that exists only to implement this one method.
public void onApplicationEvent( ApplicationEvent applicationEvent )
{
if ( applicationEvent instanceof ContextRefreshedEvent )
{
..do stuff here..
}
}
Best thing would be to leave it to Spring. Add your global object beans (which could be singletons etc..) to your application context. Make sure Spring is initialized when the application is loaded by adding ContextLoaderListener to the web.xml.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4">
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>
You can access your global objects from the WebApplicationContext anywhere in the application.