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

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 !

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.

How to initialize SpringWebAplication without dispatcher servlet?

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.

Understanding spring dispatcher servlet initialization

Here is how spring documentation recomends to initialize dispatcherServlet:
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
My question is about providing an empty param-value inside the init-param tag. Despite defining that param as context-param we still provide the empty value. Therefore contextConfigLocation should be null when passes to servlet's init() method. What's wrong, correct me please.
In Spring Web Applications, there are two types of container, each of which is configured and initialized differently.
Application Context
Web Application Context
Application context is inialised by config file's that you specified in as context-params and picked up by ContextLoaderListener. This is purely i would consider as business logic related beans.
Web application context is child of application context which may or may not be present. Each DispatcherServlet will have associated WebApplicationContext and which takes spring beans from your init-params to create context.
Whatever beans are available in the ApplicationContext can be referred to from each WebApplicationContext.
Reason why we have two different bean configurations is to keep a clear separation between middle-tier services such as business logic components and data access classes (that are typically defined in the ApplicationContext) and web- related components such as controllers and view resolvers (that are defined in the WebApplicationContext per Dispatcher Servlet).

Singleton bean in two contexts spring

I have a web application context(for DISPATCHER) and also Web Services context(for MESSAGE DISPATCHER) in a web application.
I have one bean which is singleton and i need that bean in both contexts.
if i specify the bean as singleton in both contexts then it is not singleton any more.
please suggest a solution or guide me in right direction.
<servlet>
<servlet-name>ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ws</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
If I understand your question correctly, you have a web application context (e.g. *-servlet.xml) and a root application context (e.g. applicationContext.xml). Web application context extends application context, so that it can access beans from the parent, but not the other way around, so beans which need to be accessed in both should be in applicationContext.xml
See:
Difference between applicationContext.xml and spring-servlet.xml in Spring Framework and
What is the difference between ApplicationContext and WebApplicationContext in Spring MVC? and
ContextLoaderListener or not?
Edit:
In your web.xml you have two ServletContexts, but no root context. The answer to What is the difference between ApplicationContext and WebApplicationContext in Spring MVC? has an excellent explanation of this, but in short you will need to load the root application context by adding the following to web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
which will then load the root application context from applicationContext.xml. Beans in the root application context will be accessible in both ServletContexts. You would usually want only web related beans (Controllers etc) in you ServletContexts, and shared business logic in the root application context.
If the bean needs to be used in two different contexts, define it in a separate application context xml file, then create three application contexts:
Root context - contains shared bean(s)
App context 1. e.g. web app. Has the root context as a parent.
App context 2. e.g. web services interface, also has the root context as a parent.
The bean will be instantiated once when the root application context is created. Both the child app contexts can then use that singleton bean.

About multiple containers in spring framework

In a typical Spring MVC project there two "containers": One created by ContextLoaderListener and the other created by DispatchServlet.
I want to know, are these really two IoC container instance?( I see two bean config files, one is root-context.xml the other is servlet-context.xml)
If there are 2 containers, then what's the relationship?
Can the beans declared in one container be used in the other?
From the Spring Official Website:
The interface org.springframework.context.ApplicationContext
represents the Spring IoC container and is responsible for
instantiating, configuring, and assembling the aforementioned beans.
The container gets its instructions on what objects to instantiate,
configure, and assemble by reading configuration metadata. The
configuration metadata is represented in XML, Java annotations, or
Java code.
Again from official Doc:
In the Web MVC framework, each DispatcherServlet has its own
WebApplicationContext, which inherits all the beans already defined in
the root WebApplicationContext. These inherited beans can be
overridden in the servlet-specific scope, and you can define new
scope-specific beans local to a given Servlet instance.
Now coming to your Question, as is stated here:
In Spring Web Applications, there are two types of container, each of
which is configured and initialized differently. One is the
“Application Context” and the other is the “Web Application Context”.
Lets first talk about the “Application Context”. Application Context
is the container initialized by a ContextLoaderListener or
ContextLoaderServlet defined in the web.xml and the configuration
would look something like this:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:*-context.xml</param-value>
</context-param>
In the above configuration, I am asking spring to load all files from
the classpath that match *-context.xml and create an Application
Context from it. This context might, for instance, contain components
such as middle-tier transactional services, data access objects, or
other objects that you might want to use (and re-use) across the
application. There will be one application context per application.
The other context is the “WebApplicationContext” which is the child
context of the application context. Each DispatcherServlet defined in
a Spring web application will have an associated
WebApplicationContext. The initialization of the WebApplicationContext
happens like this:
<servlet>
<servlet-name>platform-services</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:platform-services-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
You provide the name of the spring configuration file as a servlet
initialization parameter. What is important to remember here is that
the name of the XML must be of the form -servlet. xml.
In this example, the name of the servlet is platform-services
therefore the name of our XML must be platform-service-servlet.xml.
Whatever beans are available in the ApplicationContext can be referred
to from each WebApplicationContext. It is a best practice to keep a
clear separation between middle-tier services such as business logic
components and data access classes (that are typically defined in the
ApplicationContext) and web- related components such as controllers
and view resolvers (that are defined in the WebApplicationContext per
Dispatcher Servlet).
Check these links
Difference between applicationContext.xml and spring-servlet.xml in Spring Framework
http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-basics
There aren't two separate containers created. Typically, you want spring to instantiate the object declared in the servlet-context.xml when the object is required. So, you map the servlet-context.xml configuration file to the Dispatcher Servlet i.e. you want to initialize the object when a request hits the dispatcher servlet.
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Where as, if you want to initialize the object and perform action when the context is being loaded you would declare the configuration file with in the context-param tags of your deployment descriptor.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
You could test this out by writing by declaring separate beans in the servlet-context.xml and root-context.xml and then, autowiring them in a custom Context Loader Listener class. You would find only the root-context instances are initialized and servlet-context beans are null.
ApplicationContext a registry of components (beans).
ApplicationContext defines the beans that are shared among all the servlets i.e. root context configuration for every web application.
spring*-servlet.xml defines the beans that are related WebApplicationContexts here DispatcherServlet.
Spring container can have either single or multiple WebApplicationContexts.
Spring MVC have atleast 2 container -
Application Context declared by
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
Servlet context declared by -
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
And a web application can define any number of DispatcherServlet's. Each servlet will operate in its own namespace, loading its own application context with mappings, handlers, etc. Only the root application context as loaded by ContextLoaderListener, if any, will be shared. Thus can have any number of child containers.

Resources