前置内容: servlet的多种注册方式
SPI部分内容参照 servlet的多种注册方式
默认情况下,springboot 使用 embedded-tomcat,没有启用ServletContainerInitializer,这就需要我们做改造。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-tomcatartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
@SpringBootApplication
public class App extends SpringBootServletInitializer {
/* public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
*/
/* @Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(App.class);
}*/
}

@Configuration
public class SpringFilterConfiguration {
@Bean
public FilterRegistrationBean<SpringFilter1> SpringFilter1() {
FilterRegistrationBean<SpringFilter1> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new SpringFilter1());
registrationBean.setName("springfilter11");
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(11);
return registrationBean;
}
@Bean
public FilterRegistrationBean<SpringFilter2> SpringFilter2() {
FilterRegistrationBean<SpringFilter2> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new SpringFilter2());
registrationBean.setName("springfilter22");
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(22);
return registrationBean;
}
}
@HandlesTypes(WebApplicationInitializer.class) //lookup 实现WebApplicationInitializer的类
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new ArrayList<>(webAppInitializerClasses.size());
for (Class<?> waiClass : webAppInitializerClasses) {
initializers.add((WebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) { // 2. 此时值为App.class
initializer.onStartup(servletContext);
}
}
}
App为我们的主类,它的泪如如下。

程序的最终入口就在此了。
public abstract class SpringBootServletInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext rootApplicationContext = createRootApplicationContext(servletContext); // 3.1
if (rootApplicationContext != null) {
servletContext.addListener(new SpringBootContextLoaderListener(rootApplicationContext, servletContext)); //3.2
}
}
//3.1
protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
SpringApplicationBuilder builder = createSpringApplicationBuilder(); // new SpringApplicationBuilder()
builder.main(getClass()); // getClass() == App.class
//parent部分略....
builder.initializers(new ServletContextApplicationContextInitializer(servletContext)); //3.1.1
builder.contextFactory((webApplicationType) -> new AnnotationConfigServletWebServerApplicationContext()); //3.1.2 factory 直接返回new AnnotationConfigServletWebServerApplicationContext(); extends ServletWebServerApplicationContext
builder = configure(builder); //do nothing
builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext)); //3.1.3
SpringApplication application = builder.build(); // 返回 SpringApplication
application.addPrimarySources(Collections.singleton(getClass())); //3.1.4
application.setRegisterShutdownHook(false);
return run(application);
}
protected WebApplicationContext run(SpringApplication application) {
return (WebApplicationContext) application.run(); //执行 SpringApplication.run()
}
}
SpringApplication.run()的逻辑不再赘述, 最终会调用AbstractApplicationContext.onRefresh(),而此时的ApplicationContext的具体实现类为AnnotationConfigServletWebServerApplicationContext
public class SpringApplication {
private List<ApplicationContextInitializer<?>> initializers; //3.1.1
private List<ApplicationListener<?>> listeners; //3.1.3
private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT; //3.1.2
private Set<Class<?>> primarySources; //3.1.4
public ConfigurableApplicationContext run(String... args) {
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext(); // applicationContextFactory.create()//3.1.2 return AnnotationConfigServletWebServerApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context); // ConfigurableApplicationContext.refresh(); ---> AbstractApplicationContext.onRefresh();
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
callRunners(context, applicationArguments);
return context;
}
}

public class ServletWebServerApplicationContext extends GenericWebApplicationContext
implements ConfigurableWebServerApplicationContext {
@Override
protected void onRefresh() {
super.onRefresh();
createWebServer(); // factory.getWebServer(getSelfInitializer());
}
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
for (ServletContextInitializer beans : getServletContextInitializerBeans()) { beanFactory.getBeanNamesForType(ServletContextInitializer.class);
beans.onStartup(servletContext); //6
}
}
}

//6. FilterRegistrationBean -> AbstractFilterRegistrationBean -> DynamicRegistrationBean -> RegistrationBean
public abstract class AbstractFilterRegistrationBean<T extends Filter> extends DynamicRegistrationBean<Dynamic> {
@Override
protected Dynamic addRegistration(String description, ServletContext servletContext) {
Filter filter = getFilter();
return servletContext.addFilter(getOrDeduceName(filter), filter);
}
}