A standard spring web application (created by Roo or "Spring MVC Project" Template) create a web.xml with ContextLoaderListener and DispatcherServlet. Why do they not only use the DispatcherServlet and make it to load the complete configuration?

I understand that the ContextLoaderListener should be used to load the stuff that is not web relevant and the DispatcherServlet is used to load the web relevant stuff (Controllers,...). And this result in two contexts: a parent and a child context.

Background:

I was doing it this standard way for several years.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Handles Spring requests -->
<servlet>
    <servlet-name>roo</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/spring/webmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

This often caused problems with the two contexts and the dependencies between them. In the past I was always able to find a solution, and I have the strong feeling that this makes the software structure/architecture always better. But now I am facing a problem with the events of the both contexts.

-- However this makes my rethink this two context pattern, and I am asking myself: why should I bring myself into this trouble, why not loading all spring configuration files with one DispatcherServlet and removing the ContextLoaderListener completely. (I still will to have different configuration files, but only one context.)

Is there any reason not to remove the ContextLoaderListener?


In your case, no, there's no reason to keep the ContextLoaderListener and applicationContext.xml. If your app works fine with just the servlet's context, that stick with that, it's simpler.

Yes, the generally-encouraged pattern is to keep non-web stuff in the webapp-level context, but it's nothing more than a weak convention.

The only compelling reasons to use the webapp-level context are:

  • If you have multiple DispatcherServlet that need to share services
  • If you have legacy/non-Spring servlets that need access to Spring-wired services
  • If you have servlet filters that hook into the webapp-level context (e.g. Spring Security's DelegatingFilterProxy, OpenEntityManagerInViewFilter, etc)

None of these apply to you, so the extra complexity is unwarranted.

Just be careful when adding background tasks to the servlet's context, like scheduled tasks, JMS connections, etc. If you forget to add <load-on-startup> to your web.xml, then these tasks won't be started until the first access of the servlet.


You can configure the application context the other way around as well. E.g. in order to make the OpenEntityManagerInViewFilter work. Setup the ContextLoaderListener and then configure your DispatcherServlet with:

<servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value></param-value>
    </init-param>
</servlet>

Just make sure that the contextConfigLocation parameter value is empty.


I want to share what I've done on my Spring-MVC application:

  1. On the we-mvc-config.xml I added just the classes annotated with @Controller:

    <context:component-scan base-package="com.shunra.vcat">
        <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>
    
  2. On the applicationContext.xml files I added all the rest:

    <context:component-scan base-package="com.shunra.vcat">
        <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>