applicationContext.xml and dispatcher-servlet.xml

18 April 2015

I was trying to improve an existing Spring project to be able to inject Hibernate's SessionFactory but get confused where to put my Hibernate XML configuration. I initially put it within <context-param/> but was surprised Spring is not creating my sessionFactory bean. Then I tried it under <init-param/> but the result is the same, there's no sessionFactory bean. I tried putting my Hibernate configuration on both locations and it worked. I still don't understand why hence I asked my friend Google.

I found this post from Late Night Developer which helped me understand why there are two places for my custom XML configurations.

The most important thing to understand is that there are 2 layers of application contexts, and they each have default XML files to load beans from.

Root Application Context

The Root application context is created when you specify a ContextLoaderListener in your web.xml file. It allows you to define beans that will be available to all the servlet contexts. If you don't specify a listener, then there will be no Root context which is also valid. Here's how you define the ContextLoaderListener in the web.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

		<!-- Configurations for the root application context (parent context) -->
		<listener>
		    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
		</listener>

</web-app>

By default, the listener loads beans from the file /WEB-INF/applicationContext.xml. To specify an alternative file, use the contextConfigLocation context parameter in the web.xml file. In an instance,

<web-app>
    ...
    <context-param>
		    <param-name>contextConfigLocation</param-name>
		    <param-value>
		        /WEB-INF/spring/jdbc/spring-jdbc.xml
		        /WEB-INF/spring/security/spring-security-context.xml
		    </param-value>
		</context-param>
</web-app>

Servlet Application Context

Each Spring DispatcherServlet defined in the web.xml file gets its own application context. If there is a Root application context (i.e. if a ContextLoaderListener is defined), then that will be the parent of the servlet context and the beans will be available for use in the servlet context. By default, DispatcherServlet loads beans from the file /WEB-INF/<servlet-name>-servlet.xml which is widely named as dispatcher.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

		<!-- Configurations for the DispatcherServlet application context (child context) -->
    <servlet>
        <servlet-name>spring-mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

</web-app>

To change the name of the XML bean file that the servlet loads, you can use the namespace initialisation parameter, but be careful as the servlet assumes that the file is in WEB-INF, and ends in .xml, so you don't put those as part of the parameter value. This is inconsistent with the other file specifications already mentioned, which are relative to the wep app base. In an instance,

<web-app>
    ...
    <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>
                /WEB-INF/spring/mvc/spring-mvc-servlet.xml
            </param-value>
        </init-param>
    </servlet>
</web-app>