How to initialize SpringWebAplication without dispatcher servlet? - spring

I'm using Spring, but not SpringMVC in a web applcaition and gotta initialize Spring Application via web.xml
I have the standard web-project structure:
WEB-INF/applicationContext.xml
WEB-INF/web.xml
web.xml is currently contains:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
But my question was caused that any listener should be bound to a servlet. In my case I don't use dispatcherServlet. How to load spring WebApplicationContext, all spring beans, etc in that case? What do I write in web.xml?

A ContextLoaderListener initializes a WebApplicationContext and stores it in the ServletContext attributes under the name referenced by WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE.
You can retrieve it that way.
servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
anywhere you have access to the ServletContext, after the ContextLoaderListener has finished executing.
As suggested by M.Deinum in the comments, this is such a popular use case that Spring has its own utility to do it:WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext).
You don't need to change anything in your web.xml.

Related

Role of ContextLoaderListener

Besides loading optional root applicationContext for a web application what is the role of ContextLoaderListener?
In Spring docs API it says
Bootstrap listener to start up and shut down Spring's root WebApplicationContext.
From some other discussions I found that ServletContextListener creates a WebApplicationContext and WebApplicationContext provides access to the ServletContext via ServletContextAware beans and the getServletContext method.Otherwise it would need to be created manually.
But ContextLoaderListener is not mandatory. So if don't use ContextLoaderListener do we need to create WebApplicationContext manually?
The WebApplicationContext is bound in the ServletContext and is defined in your web.xml like:
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/my-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
If you dont configure it with a custom config file like previous (my-context.xml) and you omit this entry in your web.xml, Spring DispatcherServlet search and loads its configuration file using <servlet_name>-servlet.xml. In the my-context.xml like above (or in a <servlet_name>-servlet.xml) there could be defined Web Components as:
Controllers
ViewResolvers
LocaleResolvers
ThemeResolvers
If you want to have access to middle tier components (from Multi Web Components) like
DAO
Entity
Service
you need a parent Context. Therefore you could define in your web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/application-context-service.xml
/WEB-INF/config/application-context-dao.xml
</param-value>
</context-param>
ContextLoaderListener creates a root web-application-context for the web-application and puts it in the ServletContext of the root Application. DispatcherServlet creates its own WebApplicationContext and the handlers, controllers, view-resolvers etc. are managed by this WebApplicationContext.

Spring project not creating spring-config.xml

I have read some tutorials about using spring, and I've seen they speak about "spring-config.xml", but when I create a project I don't have that file, I have "application-config.xml", are they the same? Is the former the updated version of the latter? I am using Eclipse as IDE
The Spring Context only defines the concept of creating a Spring configuration where you will define spring components (beans, services, etc)
The XML itself can be named whatever you want, but in the web.xml file, you have to pass the xml name you choose to the spring context listener
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/thisXMLhaTheBestNameEver.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

JSF 2 and Spring 3 integration

In our JSF 2, spring 3 web application we have the following sets of entries in the web.xml to integrate spring and JSF
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/spring/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
And it works!
However, after going through quiet a few JSF & spring tutorials I see the need to define a RequestContextListener in addition to the ContextLoaderListener.
We have both request scope and session scope beans in our application.
Are both listeners mandatory? What is the consequence of not defining the RequestContextListener?
both are not mandatory, only the ContextLoaderListener
see
http://static.springsource.org/spring/docs/3.0.x/reference/web-integration.html
and
http://forum.springsource.org/showthread.php?t=81382
the RequestContextListener seems to be mandatory for Facelets
see http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/web/context/request/RequestContextListener.html
This listener is mainly for use with third-party servlets, e.g. the JSF FacesServlet.

java.lang.IllegalStateException: Root context attribute is not of type WebApplicationContext

I am deploying Portlets on Liferay 5.2.3 on Tomcat 6. I get this error only for one of the portlet.
java.lang.IllegalStateException: Root context attribute is not of type WebApplicationContext
I did some research and found out that Spring was instantiating a portlet application context when it need a web one. But in my web.xml I am only defining contextLoaderListner
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
And to top it off, if a different *.jar file was being looked up by Spring, then why would my other portlets get deployed except one?
After couple of redeployments I get that to a fix. Can someone put some light on?
The root cause seems to be a static variable in the portal/application server "hanging onto" an instance of a class from the portlet. Two common culprits are log4j and java logging, both of which are commonly used by application containters.
See log4j and the thread context classloader and http://logback.qos.ch/manual/loggingSeparation.html for more discussion of loggers. The suggestion is to use SLF4J with logback OR to be sure to put log4j.jar in your WAR file so it is in the right classloader (although some containers will thwart this solution).
Also, some other class that is present in the container may be the cause. Logging is just a common problem.
Sounds like you are not defining the contextConfigLocation? in web.xml you should also have something like this in addition to the contextLoaderListener:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Where applicationContext.xml is a normal config file for a webapp.
You should also have this in your web.xml if using spring portlet MVC:
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
In your portlet.xml I guess you have something like this to specify your portlets:
<portlet>
<portlet-name>sample</portlet-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>Sample Portlet</title>
</portlet-info>
</portlet>
If you haven't already, see the spring portlet mvc reference documentation
Hope it helps.

How to connect HttpServlet with Spring Application Context in web.xml?

I'm trying to connect my FooServlet which extends HttpServlet with the ApplicationContext which is in the same Project.
The Application Context is already used by a Wicket Servlet
It works with
servletContext = this.getServletContext();
wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
(IMyBean)wac().getBean("myServiceBean")
Now I try to aviod to use explicitly Spring Classes in my Code (WebApplicationContextUtils) as it's not the IoC way.
The Wicket Servlet is connected with the Application context in the web.xml
<servlet>
<servlet-name>ExampleApplication</servlet-name>
<servlet-class>org.apache.wicket.protocol.http.WicketServlet</servlet-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I found the class Spring HttpServletBean but I don't know if it serves for my Case
I found a way to inject Beans in my HttpServlet (Note: I don't need a Presentation View, otherwise there are more advanced Spring Classes)
Add a ContextLoaderListener to web.xml so that Spring's root WebApplicationContext is loaded
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Configure Servlet using Springs HttpRequestHandlerServlet Class
<servlet>
<servlet-name>FooServlet</servlet-name>
<display-name>Foo Servlet</display-name>
<servlet-class>
org.springframework.web.context.support.HttpRequestHandlerServlet
</servlet-class>
</servlet>
Let your Servlet implement the org.springframework.web.HttpRequestHandler Interface
Define your Servlet as a Bean in ApplicationContext (beanID must be same as "servlet-name").
Now it's possible to inject all necassary Beans in the Spring DependencyInjection way without dependency lookup.
I think you should use Spring utilities like
RequestContextUtils.getWebApplicationContext(request, application);
to hookup the Spring Context within your Servlet.
Agreed this is no DI/IoC, but the servlet is no bean as well !

Resources