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.
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.