Spring Boot提供的在Servlet 3.0+环境中用于程序化配置ServletContext的接口。该接口ServletContextInitializer主要被RegistrationBean实现用于往ServletContext容器中注册Servlet,Filter或者EventListener。这些ServletContextInitializer的设计目的主要是用于这些实例被Spring IoC容器管理。这些ServletContextInitializer实例不会被SpringServletContainerInitializer检测,因此不会被Servlet容器自动启动。
该接口ServletContextInitializer和Spring Web的另外一个接口WebApplicationInitializer看起来几乎一模一样。但二者使用目的不同。Spring Web中,WebApplicationInitializer也是针对Servlet 3.0+环境,设计用于程序化配置ServletContext,跟传统的web.xml相对或者配合使用。WebApplicationInitializer实现类会被SpringServletContainerInitializer自动检测和启动。
关于ServletContextInitializer的应用可以参考下面的例子。TomcatStarter是Spring Boot Web Servlet应用结合Tomcat使用时的一个ServletContainerInitializer实现。从下面代码不难看出,一组ServletContextInitializer会被设置到ServletContainerInitializer TomcatStarter上,而TomcatStarter在Servlet容器启动过程中调用自己的方法#onStartup,会逐一调用这些ServletContextInitializer的方法#onStartup初始化ServletContext。
package org.springframework.boot.web.embedded.tomcat; import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.boot.web.servlet.ServletContextInitializer; class TomcatStarter implements ServletContainerInitializer { private static final Log logger = LogFactory.getLog(TomcatStarter.class); // 使用者会指定一组 ServletContextInitializer 给 TomcatStarter private final ServletContextInitializer[] initializers; private volatile Exception startUpException; TomcatStarter(ServletContextInitializer[] initializers) { this.initializers = initializers; } // Servlet 容器启动时回会用该方法,该方法会逐一调用每个 ServletContextInitializer 的方法 // #onStartup 会指定 ServletContext 进行初始化。这些 ServletContextInitializer 的目的 // 通常会是 注册 Servlet, Filter 或者 EventListener 。 @Override public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException { try { for (ServletContextInitializer initializer : this.initializers) { initializer.onStartup(servletContext); } } catch (Exception ex) { this.startUpException = ex; // Prevent Tomcat from logging and re-throwing when we know we can // deal with it in the main thread, but log for information here. if (logger.isErrorEnabled()) { logger.error("Error starting Tomcat context. Exception: " + ex.getClass().getName() + ". Message: " + ex.getMessage()); } } } public Exception getStartUpException() { return this.startUpException; } }源代码版本 : 2.1.3.RELEASE
package org.springframework.boot.web.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.springframework.web.SpringServletContainerInitializer; import org.springframework.web.WebApplicationInitializer; @FunctionalInterface public interface ServletContextInitializer { /** * Configure the given ServletContext with any servlets, filters, listeners * context-params and attributes necessary for initialization. * @param servletContext the ServletContext to initialize * @throws ServletException if any call against the given ServletContext * throws a ServletException */ void onStartup(ServletContext servletContext) throws ServletException; }