Using STS in eclipse to create an mvc project I notice that the servlet-context.xml seems to be written to be used in both the root context and the dispatcherservlet Context. I say this because I notice that the context:component-scan is in it, which is often loaded into the root context, but it is loaded into the dispatcherservlet context. I also noticed a sample spring mvc/jpa project - http://duckranger.com/2012/04/spring-mvc-3-x-with-sts-tutorial-part-iii-add-some-jpa/ - that specifically loads the servlet-context.xml into both contexts. I thought the idea was to keep a clean separation between the contexts. Can someone explain this to me?
The following configuration is plain wrong
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:META-INF\root-context.xml
classpath:META-INF\servlet-context.xml
classpath:META-INF\datasource.xml
</param-value>
</context-param>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF\servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Your root and servlet context should NEVER import the same files, as the beans from the root context will already be available in the servlet context because of the context hierarchy in Spring. There is no point to create copies of them in the different contexts(especially because the beans in the root context will be shadowed by the ones in the servlet context, for example if you declare <tx:annotation-driven> only in the root context it will not affect the behavior of the servlet context beans, which will force you to tangle configuration even more) .
It's very illogical to put <jpa:repositories> into the servlet context, because it's VERY likely that you will use the repositories from the service layer.
Typically you should not put anything but the MVC configuration to the servlet context. It's the root web app context where the services should live. Servlet context provides separation of the controllers from the services, so when you test your services with Spring Test Context framework you don't have to create the controllers(if you want to test the mappings you should use Spring MVC Test framework) and test the application services directly.
To be clear, if we examine the figure from the Hexagonal Architecture article
the the servlet context should contain only user-side API related things but not the application. It is arguable whether you should divide the configuration of the root web app context and put data-side-api into separate configuration file but the question was about servlet/root contexts.
Just to be less abstract here's some informal diagram of what I typically keep in mind(in terms of Spring contexts and bean configuration files) when configure a Spring application(of course it's all subjective, it's not a super solution and actually is a bit over complicated - it's unlikely that I will need so many servlets and configuration files)
Related
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.
I am working on a Spring application. I started from creating a small java app using spring. Later, it became necessary to add a web interface. I decided to use Spring MVC. Now I am confused. In my web.xml I have
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/mvc-dispatcher-servlet.xml,
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
where mvc-dispacher-servlet.xml contains beans necessary for web logic while applicationContext.xml contains beans performing some specific operations. My question is: Are beans in these files going to be aware of each other? Is it going to be a one big container which includes beans from both config files? or these containers are separate?
Yes it will be in one context which will be loaded from the web application context. Its the same as you would do when using the application context and passing in multiple files to it.
What is the difference between Application Context and Web Application Context?
I am aware that WebApplicationContext is used for Spring MVC architecture oriented applications?
I want to know what is the use of ApplicationContext in MVC applications? And what kind of beans are defined in ApplicationContext?
Web Application context extended Application Context which is designed to work with the standard javax.servlet.ServletContext so it's able to communicate with the container.
public interface WebApplicationContext extends ApplicationContext {
ServletContext getServletContext();
}
Beans, instantiated in WebApplicationContext will also be able to use ServletContext if they implement ServletContextAware interface
package org.springframework.web.context;
public interface ServletContextAware extends Aware {
void setServletContext(ServletContext servletContext);
}
There are many things possible to do with the ServletContext instance, for example accessing WEB-INF resources(xml configs and etc.) by calling the getResourceAsStream() method.
Typically all application contexts defined in web.xml in a servlet Spring application are Web Application contexts, this goes both to the root webapp context and the servlet's app context.
Also, depending on web application context capabilities may make your application a little harder to test, and you may need to use MockServletContext class for testing.
Difference between servlet and root context
Spring allows you to build multilevel application context hierarchies, so the required bean will be fetched from the parent context if it's not present in the current application context. In web apps as default there are two hierarchy levels, root and servlet contexts: .
This allows you to run some services as the singletons for the entire application (Spring Security beans and basic database access services typically reside here) and another as separated services in the corresponding servlets to avoid name clashes between beans. For example one servlet context will be serving the web pages and another will be implementing a stateless web service.
This two level separation comes out of the box when you use the spring servlet classes: to configure the root application context you should use context-param tag in your web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/root-context.xml
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
(the root application context is created by ContextLoaderListener which is declared in web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
)
and servlet tag for the servlet application contexts
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>app-servlet.xml</param-value>
</init-param>
</servlet>
Please note that if init-param will be omitted, then spring will use myservlet-servlet.xml in this example.
See also: Difference between applicationContext.xml and spring-servlet.xml in Spring Framework
The accepted answer is through but there is official explanation on this:
The WebApplicationContext is an extension of the plain ApplicationContext that has some extra features necessary for web applications. It differs from a normal ApplicationContext in that it is capable of resolving themes (see Using themes), and that it knows which Servlet it is associated with (by having a link to the ServletContext). The WebApplicationContext is bound in the ServletContext, and by using static methods on the RequestContextUtils class you can always look up the WebApplicationContext if you need access to it.
Cited from Spring web framework reference
By the way servlet and root context are both webApplicationContext:
Going back to Servlet days, web.xml can have only one <context-param>, so only one context object gets created when server loads an application and the data in that context is shared among all resources (Ex: Servlets and JSPs). It is same as having Database driver name in the context, which will not change. In similar way, when we declare contextConfigLocation param in <contex-param> Spring creates one Application Context object.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.myApp.ApplicationContext</param-value>
</context-param>
You can have multiple Servlets in an application. For example you might want to handle /secure/* requests in one way and /non-seucre/* in other way. For each of these Servlets you can have a context object, which is a WebApplicationContext.
<servlet>
<servlet-name>SecureSpringDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>com.myapp.secure.SecureContext</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SecureSpringDispatcher</servlet-name>
<url-pattern>/secure/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>NonSecureSpringDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>com.myapp.non-secure.NonSecureContext</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>NonSecureSpringDispatcher</servlet-name>
<url-pattern>/non-secure/*</url-patten>
</servlet-mapping>
ApplicationContext (Root Application Context) :
Every Spring MVC web application has an applicationContext.xml file which is configured as the root of context configuration. Spring loads this file and creates an applicationContext for the entire application.
This file is loaded by the ContextLoaderListener which is configured as a context param in web.xml file. And there will be only one applicationContext per web application.
WebApplicationContext :
WebApplicationContext is a web aware application context i.e. it has servlet context information.
A single web application can have multiple WebApplicationContext and each Dispatcher servlet (which is the front controller of Spring MVC architecture) is associated with a WebApplicationContext. The webApplicationContext configuration file *-servlet.xml is specific to a DispatcherServlet.
And since a web application can have more than one dispatcher servlet configured to serve multiple requests, there can be more than one webApplicationContext file per web application.
Web application context, specified by the WebApplicationContext interface, is a Spring application context for a web applications. It has all the properties of a regular Spring application context, given that the WebApplicationContext interface extends the ApplicationContext interface, and add a method for retrieving the standard Servlet API ServletContext for the web application.
In addition to the standard Spring bean scopes singleton and prototype, there are three additional scopes available in a web application context:
request - scopes a single bean definition to the lifecycle of a single HTTP request; that is, each HTTP request has its own instance of a bean created off the back of a single bean definition
session - scopes a single bean definition to the lifecycle of an HTTP Session
application - scopes a single bean definition to the lifecycle of a ServletContext
I'm new to Java Enterprise and to Spring but I have a strong grasp of standard Java. I am looking through an existing web application project. The project uses Tomcat/Spring/Hibernate which I understand is fairly common. It also uses DWR for remote method invocations. I'm finding it somewhat difficult to separate responsibilities: what Tomcat is responsible for, what Spring is responsible for, how a request gets from one to the other, and how the major pieces of Spring fit together. I've read a great deal of documentation on Spring, particularly about beans and bean factory and am still in process of reading more. Any advice you guys have would be welcome, but I'll provide some specific questions.
Question 1: Where does the web.xml fit into things (when is it used/called, and where is it called from)?
Code sample 1:
<servlet>
<servlet-name>qrst</servlet-name>
<display-name>qrst Servlet</display-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
What does the above snippet do (or, what does it cause to happen)? At some point in my web app qrst.jsp gets used; is it the DispatcherServlet that calls qrst.jsp using the servlet name? Else what is the significance of the servlet name? What is load on startup?
Code sample 2:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/someLocation/some-servlet.xml
</param-value>
</context-param>
Links or explanation of what the above does? I can see from looking at the XML file that it contains bean definitions and I do understand what beans are and how they are used, but I don't know any other details about this and would like to.
Code sample 3:
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR</display-name>
<servlet-class>
org.directwebremoting.servlet.DwrServlet
</servlet-class>
<init-param>
<param-name>classes</param-name>
<param-value>
somepackage.someclass
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
From what I read about beans, I believe those init-param elements are just parameters that get set in the servlet's java class. What's the significance of the servlet name, and what about the load on startup? The web app somehow "knows" when an AJAX (dwr) call is happening versus when the web app is being loaded for the first time (when its loading for the first time it should use qrst.jsp). How does it know this? How does it decide to route the request to DWR instead of to qrst.jsp? Where does it do this?
Thanks.
Servlets are JavaEE's idiom for answering HTTP requests. You program the behavior of your application in a Servlet which will respond to a request.
Tomcat is a Servlet container, which means you deploy your application in Tomcat and it will manage all the communication infrastructure for you: it accepts connections, manages database connections(*) and will call upon your servlets to handle incoming requests.
web.xml is part of any JavaEE application, not Spring. Your code sample 1 declares that your app will use an instance of class org.springframework.web.servlet.DispatcherServlet to handle incoming requests.
Although servlets are the basic foundations for JavaEE development, it is not advised to create your own; instead, with Spring, you create MVC controllers. Then the DispatcherServlet will call upon these controllers to handle the requests. It's just another indirection (but a very powerful one!)
is it the DispatcherServlet that calls qrst.jsp using the servlet name?
Not directly. It's just a coincidence that your servlet and the JSP file have the same name.
What is loaded on startup?
Your code sample 2 instructs the DispatcherServlet to load the beans from file /someLocation/some-servlet.xml. If there are controller beans in this file and according to how you configured the url mapping, beans from this file will answer the incoming requests. See the reference.
I believe those init-param elements are just parameters that get set in the servlet's java class
The init-param elements in web.xml are for the servlet class.
The web app somehow "knows" when an AJAX (dwr) call is happening versus when the web app is being loaded for the first time (when its loading for the first time it should use qrst.jsp). How does it know this?
Missing from the question are either the <servlet-mapping> element (found in web.xml), or the url mappings (found in the spring files). These are responsible for deciding whether an URL should be handled by the dispatcher servlet or the dwr servlet.
For instance, with an servlet mapping like below:
<servlet-mapping>
<servlet-name>qsrt</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dwr</servlet-name>
<url-pattern>*.dwr</url-pattern>
</servlet-mapping>
Then all URLs ending in .do will be answered by the dispatcher servlet, and those ending with .dwr will be handled by the dwr servlet. Here's where the names of the servlets are important.
JSP files are a different story. The container will simply use them to handle a URL ending in *.jsp. Do not create your onw servlet mapping for URLs ending in *.jsp. This will only cause headaches. This is probably unspecified behavior.
Edit:
However, the URL in the browser's address bar always looks the same: it would always invoke the qrst servlet
Then it is possible that your servlet-mapping is so broad (something like: <url-pattern>/*</url-pattern>) that it will handle anything you throw at the server and never give a chance for the other servlets to handle it.
Last but not least, when working with DWR or any Ajax technology, install the HttpFox extension for Firefox so you can monitor the Ajax calls of your application.
We need to load the spring application context in our web application after one of our servlets is initialized, so I wonder what is the best way to do it?
I know that it's recommended to use the listener in web.xml, but it's obviously not good for us because in this case the context will be loaded before the first servlet. I saw that there was this class - ContextLoaderServet - in Spring 2.5, but it's absent in Spring 3.0. So I guess we should write some dummy servlet ourselves with the sole purpose of loading the context? Is there any better way?
Thanks.
OK, so if you have this legacy servlet that sets stuff up, then you will need to persuade the Spring servlet to load after it.
This is straightforward - use Spring's DispatcherServlet to load the Spring context, and use the standard <load-on-startup> in web.xml to dictate the startup order, e.g.
<servlet>
<servlet-name>LegacyServlet</servlet-name>
<servlet-class>com.xy.LegacyServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>SpringServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>