What is ContextLoaderListener role and purpose

First we shoud clarify some confusing concepts, there are many different combinations but at the core are four basic ideas: container, context, application and servlet. In essence, it's an ontology problem, because some words are overloaded heavily.

Web container or servlet container as its name indicated is a container that holds servlet. The container act as a proxy or bridge between web server and servlet, what the container do is to take care of all the chores to make the web server and servlet can corporate with each other. On one side, the web server can talk with the container in web semantics, it's called web container. On the other side, the servlet talk with the container in servlet semantics, it's called servlet container. The two semantics are quite different, like two different languages, and both want to focus on their own business, here is where the container comes in as a sort of translator.

Here are some tasks the container do:

  • Manages the life cycle of servlet, create, instantiate, initialization, destroy, etc
  • Read configurations from XML descriptor file
  • Mapping between URL and servlet

Even in a PHP application, there must be a "PHP container", someone has to execute PHP interpreter, set up environment and send the response back to web server. It's just not called container, it's called a mod and it's much less configurable and flexible than Java container. PHP developers almost never need to worry about how the mod works and rarely talk about it. To set URL mapping, a PHP developer has to configure the web server, while a JAVA developer can configure it in servlet container. Because of this configurability, the container exposes some details about itself to end developers, thus they need to know how the container works to properly configure it.

Context is another overloaded word, in software it's sometimes exchangeable with runtime or environment or container. You hear concepts like servlet context, application context, web application context, etc. When people refers application context, they means the IoC container which holds and wires Spring beans to provide dependency injection mechanism in general. In general means this context is about the beans for the whole application in general, Spring is a Framework, it can be used to develop all kinds of applications, the web application is one of them. When it's a web application, the beans relate to web application such as controllers , services, view resolvers are stored in a separate bean container, this context will be called web application context, in Spring, these context are linked as a hierarchical structure with the application context as root and the other contexts as children. The application context is also called root context.

Just like beans live in Spring IoC container which creates and maintains a context for the beans. Servlet also lives in the web container which creates and maintains a context, called servlet context. Just like Spring is a framework, the web container is also a framework which has many callbacks that are invoked in appropriate times and at appropriate places. Your code actually lives in a framework within another framework, a container within another container, a context within another context, callbacks within other callbacks. Welcome to the world of modern application development.

The whole system is event driven, the container is the pumping loop, it starts up, initializes the environment and handles the request from webserver whenever they reach. On the execution path of the container, there are callback points in the form of filters and listeners. You can register your own code to these points so they can be invoked at desired moments. There are many different type of filters and listeners, this post will foucs on type of listener categorized as Servlet context lifecycle changes. This listener is called when the servlet context object is created by web container. Spring framework registers the class ContextLoaderListener as the listener.

ContextLoaderListener bootstrap a WebApplicationContext in the ServletContext. That is, it creates a root application context for the web application and puts it in the ServletContext.

Bootstrap here means it's the first point where you can create an application context, and this will be the root context.

The best way to understand how it works is to look at the source code of class ContextLoader from which ContextLoaderListener extends, it contains the working code for bootstrapping the root application context.

 
https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java
 

In Spring, you can have multiple application contexts and they are organized in hierarchical structures, for example, each DispatcherServlet can have its own application context, these contexts will be child context of the root context, a child context can access beans in the parent context, but not vice versa.

All the application contexts are optional, you can have only Servlet context (you are only using Spring MVC), or only root application context(you are using Spring but with Struts as MVC framework), or both(you are using Spring MVC and Spring Security). But you need at least one to use the Spring IoC , injecting and bean facility. This makes Spring very flexible, easy to integrate with other frameworks, it not force you to use one technology. When you are using Struts and Spring together, from the perspective of Struts , Spring is just a library with the root application context instance as entry point.

Root Application context is also used by other components of Spring framework, for example the Spring Security, all the spring security related beans are stored in root context, it's not a part of MVC, you need to configure ContextLoaderListener when you are using Spring Security, this makes the security component pluggable, you can use other implementations if you want, just like you can use other MVC implementations. They are loosely coupled and can be replaced easily.

After the root application context is created, it's stored in ServletContext as an attribute, the name is

 
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
 

How to get root application context in Spring controller

We know the application is stored in ServletContext, to access it, we need a reference to ServletContext, this is easy in Spring with autowired. Spring also provided a convenience method to helps us to get the root application context, the WebApplicationContextUtils.

 
 
  @Autowired
  ServletContext context; 
 
  public String testRootContext() {
      ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(context);
      if(ac == null){
          return "root application context is null";
      } else {
          return "root application is set";
      }      
  }
 

This is actually how root application context is retrieved if you look at the code in method initWebApplicationContext in

 
https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java
 

The code look like below

 
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
 
        if (this.webApplicationContext != null) {
            // A context instance was injected at construction time -> use it
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent -> set
                        // the root application context (if any; may be null) as the parent
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
 

This method creates web application context when creating ServletDispatcher, and set the root application context as the web application context's parent.

In this example: Gradle build Spring4 MVC Hello World Example, only the Spring MVC is used and configured, there is no application context, the output will be

Configure root application context

In web.xml

 
<listener>
  <listener-class>
    org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>
 
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/spring/*.xml</param-value>
</context-param>
 

In annotation, take the Spring Security as example:

 
            AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
            rootAppContext.register(configurationClasses);
            servletContext.addListener(new ContextLoaderListener(rootAppContext));
 

Fortunately, you don't have to this, there is an implementation provided by Spring, you can simply extends it:

 
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    public SecurityWebApplicationInitializer() {
        super(ExampleSecurityConfiguration.class);
    }
}
 

In the onStartup method, the root context will be created and listener will be added.