Skip to content

SpringServletContainerInitializer

ServletContainerInitializer(in org.springframework.web) is the interface which allows a library/runtime to be notified of a web application’s startup phase and perform any required programmatic registration of servlets, filters, and listeners in response to it.

The spring also has an implementation for it. That is ServletContainerInitializer, When you started a spring apllication, it will be loaded and instantiated and have its onStartup method invoked by any Servlet-compliant container during container startup assuming the the spring-web moodule JAR is present on the classpath.

Assuming that one or more WebApplicationInitializer types are detected, they will be instantiated Then the WebApplicationInitializer.onStartup(ServletContext) method will be invoked on each instance, delegating the ServletContext such that each instance may register and configure servlets(Spring’s DispatcherServlet(), listeners(Spring’s ContextLoaderListener), or any other Servlet API features(filters).

Below is the code for SpringServletContainerInitializer.

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = Collections.emptyList();
if (webAppInitializerClasses != null) {
initializers = new ArrayList<>(webAppInitializerClasses.size());
for (Class<?> waiClass : webAppInitializerClasses) { //--------------------------------(1)
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext); //--------------------------------(2)
}
}
}

A brief description of the action it performs is as follows :

  1. Repeat the Set <Class<?> received as a parameter to create a Web Application Initializer and put it in the initializers.
  2. Sort the initializers and run the WebApplicationInitializer#onStartup method.

If then, what is WebApplicationInitializer?

WebApplicationInitializer

WebApplicationInitializer is the Interface to be implemented in Servlet environments in order to configure the ServletContext programmatically.

As you can see from above, Implementations of this SPI will be detected automatically by SpringServletContainerInitializer, which itself is bootstrapped automatically by any Servlet container.

public interface WebApplicationInitializer {
/**
* Configure the given {@link ServletContext} with any servlets, filters, listeners
*/
void onStartup(ServletContext servletContext) throws ServletException;
}

public class MyWebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext =
new AnnotationConfigWebApplicationContext();
dispatcherContext.register(DispatcherConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}

By implementing this WebApplicationInitializer, you can set the WebApplication in detail based on code. (like above)

There are several implementations of the WebApplicationInitializer that are provided by default. AbstractAnnotationConfigDispatcherServletInitializer is the base class to initialize Spring application in Servlet container environment, so we will check that class and its parent class.

AbstractAnnotationConfigDispatcherServletInitializer

It is constructed like “Decorator Pattern”.

If look at the order of operation from the bottom,

  • AbstractAnnotationConfigDispatcherServletInitializer registers the ContextLoaderListener, including the settings of the class with the specific Annotation(@Configuration), and creates the ServletApplicationContext,
  • AbstractContextLoaderInitializer registers the ContextLoaderListener,
  • AbstractDispatcherServletInitializer creates DispatcherServlet by register ServletFilters on servletContext,

The order of execution is the order of calls, not the parent-child order. To explain it in detail by looking at the code,

//in AbstractAnnotationConfigDispatcherServletInitializer.java
@Override
@Nullable
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(configClasses);
return context;
}
else {
return null;
}
}
  1. AbstractAnnotationConfigDispatcherServletInitializer registers the ContextLoaderListener, including the settings of the class with the specific Annotation(@Configuration), and creates the ServletApplicationContext,

//in AbstractContextLoaderInitializer.java
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
}
protected void registerContextLoaderListener(ServletContext servletContext) {
WebApplicationContext rootAppContext = createRootApplicationContext(); //Result of AbstractAnnotationConfigDispatcherServletInitializer's createRootApplicationContext()
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
  1. AbstractContextLoaderInitializer registers the ContextLoaderListener,

//in AbstractDispatcherServletInitializer
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext); //It is equel to AbstractContextLoaderInitializer's onStartup method
registerDispatcherServlet(servletContext);
}
protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
Assert.state(StringUtils.hasLength(servletName), "getServletName() must not return null or empty");
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.state(servletAppContext != null, "createServletApplicationContext() must not return null");
...
}