Can someone explain the Spring web.xml file? - spring

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.

Related

Is the load-on-startup tag in web.xml mandatory?

Is the load-on-startup tag a mandatory tag in web.xml to load dispatcher servlet in spring? Will our dispatcher servlet get initialized if it doesn't mention this tag?
yes it's required, if you expect to dispatch or render anything using spring.
No, it is not mandatory. If you do not specify "load-on-startup" tag, your project will still work fine, except for the fact that the servlet will take slightly more time to load for the first request. This tag is helpful if you have multiple servlets and you want to control the loading flow. If you have multiple servlets, then the servlet which has the least "load-on-startup" value will be loaded first.
In the below example, servlet1 will be loaded first, then servlet2 will be loaded, and so on.
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>X</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>servlet2</servlet-name>
<servlet-class>Y</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

Spring MVC DispatcherServlet mapping / vs /*

<servlet>
<servlet-name>springmvcdemo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvcdemo</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
vs
<servlet>
<servlet-name>springmvcdemo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvcdemo</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
I know there are duplicated questions but i'm still confused. My understanding is that when using /* , every request will go through this servlet (It means all .jsp, .html,etc will end up in this ). / will make this servlet the default servlet ( if there are exact URL installed..., return ) But it seem to me that when using / every request all still go through The DispatcherServlet no matter what. I can't open any .jsp file directly. Can someone explain to me more about this?
As per the Servlet specification, mapping for "/" means default servlet meaning if there is no explicit servlet matching the request, then this default servlet would be serving the request. For e.g., there is a servlet named "default" defined in Tomcat server common configuration web.xml which is inherited by all applications. This servlet serves the static contents like css,images etc which are typically not mapped in applications web.xml. Similarly there is a special Servlet which handles requests for jsp files ( all request ending with *.jsp as naturally these will be needed to be compiled to Servlets which would then process the request). So if you override the default servlet to be any other servlet in the application web.xml, then all requests not handled by any other servlet goes to this servlet and if this Servlet is not capable to serving request, it will not work.
If you declare Spring dispatcher servlet as the default Servlet, then you will not be able to serve static contents from container provided Servlet. Instead there is a special handler provided which can load static resources from configurable path pattern from directory / classpath. You need to use <mvc:resources/> tag for this feature. However if you still want to use container provided Servlet for serving resource you would need to use
<mvc:default-servlet-handler/> in the spring configuration. You can read more about this approach and its prons/cons here - section 15.12.4

spring servlet-context in sts

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)

Tomcat serving static resources on Spring MVC app

I'm building a Spring MVC application, and the frontController servlet is mapped in "/" intercepting all requests, I'd to be able to serve the static contents (.js,.css,.png...) from tomcat and not by Spring.
My app structure is
-webapp/
styles/
images/
WEB-INF/
views/
By default, because the frontController is mapped on the context root of my app its handles all requests but don't serve any static resource.
The mvc configurarion for static resources is follow.
<mvc:resources mapping="/resources/**" location="/"/>
And the page's code is:
<img src="resources/images/logo.png" />
I need to configure Tomcat to serve the static resources with no spring interaction.
Any suggestion?
You can remap tomcats default servlet (which handles static content), e.g.
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/images/*</url-pattern>
</servlet-mapping>
Have a look at this mailing list thread and see if that does what you're looking for.
Another potential solution - Just add the following to your Spring DispatcherServlet.xml (Spring Docs)
<mvc:default-servlet-handler/>
This tag allows for mapping the DispatcherServlet to "/" (thus overriding the mapping of the container's default Servlet), while still allowing static resource requests to be handled by the container's default Servlet. It configures a DefaultServletHttpRequestHandler with a URL mapping (given a lowest precedence order) of "/**". This handler will forward all requests to the default Servlet.
Pros (as compared to #nos's solution)
The URL remapping solution behaves differently depending upon your container. Jetty/Tomcat 6 take that to mean 'map URL/images/* to WEBAPP/images/'. Tomcat < 6 (and maybe others) take that to mean 'map URL/images/ to WEBAPP/*', which is a BIG security breach.
If you want to serve a favicon.ico, robots.txt etc. from your site, then you'll have
to create additional url-mappings for them.
Cons
Spring is in the loop, which is definitely something that is unnecessary.
Additionally, irrespective of the solution that one prefers, I'd suggest adding the following to your web.xml to prevent directory listings (on, say URL/images)
<servlet>
<servlet-name>default</servlet-name>
<init-param>
<param-name>dirAllowed</param-name>
<param-value>false</param-value>
</init-param>
</servlet>

Loading spring context in web application after some servlet

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>

Resources