嵌入式的 Servlet 3.0+ 容器不会直接使用 ServletContainerInitializer 和 WebApplicationInitializer,即通过以上两个接口实现的(Servlet、Filter、Listener)配置是无效的,这是为了防止第三方代码的设计损坏应用程序,原文如下
Embedded servlet containers will not directly execute the Servlet 3.0+ javax.servlet.ServletContainerInitializer interface, or Spring’s org.springframework.web.WebApplicationInitializer interface. This is an intentional design decision intended to reduce the risk that 3rd party libraries designed to run inside a war will break Spring Boot applications.
If you need to perform servlet context initialization in a Spring Boot application, you should register a bean that implements the org.springframework.boot.context.embedded.ServletContextInitializer interface. The single onStartup method provides access to the ServletContext, and can easily be used as an adapter to an existing WebApplicationInitializer if necessary.
由上可知,我们可以使用替代方案:ServletContextInitializer
@Configuration
public class GoServletContextInitializer implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//Log4j Config Listener
servletContext.setInitParameter("log4jConfigLocation", "classpath:config/properties/log4j.properties");
servletContext.addListener(Log4jConfigListener.class);
//CharacterEncodingFilter
FilterRegistration.Dynamic characterEncodingFilter =
servletContext.addFilter("characterEncodingFilter", CharacterEncodingFilter.class);
characterEncodingFilter.setInitParameter("encoding", "UTF-8");
characterEncodingFilter.setInitParameter("forceEncoding", "true");
characterEncodingFilter.addMappingForUrlPatterns(
EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE),
false, "/*");
//statViewServlet
StatViewServlet statViewServlet = new StatViewServlet();
ServletRegistration.Dynamic dynamic = servletContext.addServlet(
"statViewServlet", statViewServlet);
dynamic.setLoadOnStartup(2);
dynamic.addMapping("/druid/*");
}
}
亲测,即使将 Spring Boot 打包成 war,并部署到 Tomcat 8.5,这份配置也是有效的
第二种方案:ServletContextInitializer 的延伸
请看继承体系
位于最下边的三个类都能实现运行时注册(Servlet、Listener、Filter):
1. ServletRegistrationBean 在系统初始化时向 ServletContext 注册其包含的一个 Servlet,我们可以事先设置它的 Servlet,再把它定义为一个 Bean
2. ServletListenerRegistrationBean 在系统初始化时向 ServletContext 注册其包含的一个 ServletContextListener,我们可以事先设置它的 Listener,再把它定义为一个 Bean
3. AbstractFilterRegistrationBean 通过抽象模板方法 getFilter(),将构建 Filter 的具体细节开放给子类,而其会在系统初始化时向 ServletContext 注册这个 Filter,对此,我们可以定义一个派生类,重写该模板方法以返回我们需要构建的 Filter,最后把它定义为一个 Bean