Overriding Spring Beans in a Servlet Context

A neat little trick I’ve recently picked up is the ability to override spring bean definitions in a web application, but inside the servlet context. I was always under the impression that only one spring application context was loaded for the entire web application, but in fact it appears that its actually loaded for each DispatcherServlet you have registered in your web.xml. I know, a slight oversight on my part. To be fair, most web apps I’ve worked with have only had one DispatcherServlet declared, so perhaps I can be forgiven for my short sighted ignorance 🙂

I’m definitely no Michealangelo when it comes to anything graphic, but here is a quick diagram illustrating what I’m going on about.

Illustration of how to override a spring bean definition to provide a custom bean for that Dispatcher Servlet application context.

The crux of this example lies in the web.xml.


<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_2_5.xsd" version="2.5">

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/default-spring-context.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
<servlet-name>spring-mvc-default</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>spring-mvc-default</servlet-name>
<url-pattern>/default/*</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>spring-mvc-custom</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/default-spring-context.xml,classpath:/dispatcher-context.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>spring-mvc-custom</servlet-name>
<url-pattern>/custom/*</url-pattern>
</servlet-mapping>

</web-app>

Notice how the spring-mvc-default has its contextConfigLocation init-param value set to nothing, leaving it up to the ContextLoaderListener to load it from the declared ContextParam declared in the beginning, and also how the spring-mvc-custom has it’s contextConfigLocation init-param value of set to the default and the dispatcher specific config file.

I’ve found this quite useful in some of the web apps I’ve been building where I need a specific type of bean to be injected instead of the default one declared. Something to also note here is that in each ServletContext(i.e. each DispatcherServlet definition), they cannot see the customised beans that are being used by any of the others. Each DispatcherServlet loads its own isolated Application Context.

Update: If you’d like top see this in action, albeit a very contrived example then head over to github here,