1,SpringBoot初始化
1, Springboot版本
Springboot版本 2.1.7.RELEASE
2, 文章主要解决的问题
1,主要看一下 ServletContainerInitializer 和 ServletContextInitializer 在Springboot中的使用, ServletContextInitializer 是如何在初始化时被调用的。
2, TomcatStart怎么将tomcat启动(ServletContainerInitailizer)与spring的ServletContextInitializer 绑定的
3, SpringApplication.run(SecurityApplication.class, args) 启动
最后调用了AbstractApplicationContext的onRefresh方法, 这是一个抽象类。 onRefresh方式没有实现。<br />!
4, ServletWebServerApplicationContext继承了AbstractApplicationContext。
我用的SpringBoot版本是初始化时实际是调用了这个类里的onrefresh方法。
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
是后续调用ServletContextInitializer 的关键, this.getSelfInitializer() 这里创建了一个ServletContextInitializer****匿名内部类, 相当于一个回调。
5, factory.getWebServer获取WebServer的工厂类
factory.getWebServer 获取WebServer的工厂实现。 我们使用的是tomcat
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
.....
// 这个类是关键 做一些准备工作
this.prepareContext(tomcat.getHost(), initializers);
return this.getTomcatWebServer(tomcat);
}
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
File documentRoot = this.getValidDocumentRoot();
TomcatEmbeddedContext context = new TomcatEmbeddedContext();
.....
// 把ServletContextInitializer的实现都合并起来 [1]
ServletContextInitializer[] initializersToUse = this.mergeInitializers(initializers);
// 这个方法最重要的是把TomcatStarter添加到了tomcat容器ContextServletContainerInitializer集合中
// 容器创建完成后会遍历调用ContextServletContainerInitializer的onStartUp方法。
this.configureContext(context, initializersToUse);
this.postProcessContext(context);
}
protected void configureContext(Context context, ServletContextInitializer[] initializers) {
// [2]
TomcatStarter starter = new TomcatStarter(initializers);
//把TomcatStarter添加到了tomcat容器ContextServletContainerInitializer集合中
context.addServletContainerInitializer(starter, NO_CLASSES);
.........
}
[1] 处合并返回的 ServletContextInitializer[] initializersToUse
[2] 通过构造器的方式把[1]处获取的ServletContextInitializer[] 设置到了 TomcatStarter的属性值中。
**private final **ServletContextInitializer[] initializers;
在tomcat调用ServletContainerInitializer#onStartUp方法时TomcatStarter会遍历这三个实现类
注意第三个是ServletWebServerApplicationContext&lambda, 是通过this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});创建添加的。所以onStartUp调用的是this.getSelfInitializer()方法
6, TomcatStarter ServletContainerInitializer的实现类
class TomcatStarter implements ServletContainerInitializer {
// ServletContextInitializer是Spring中维护的接口
private final ServletContextInitializer[] initializers;
TomcatStarter(ServletContextInitializer[] initializers) {
this.initializers = initializers;
}
// tomcat容器启动最后会调用这个方法,这是servlet3.0时添加的
public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
ServletContextInitializer[] var3 = this.initializers;
int var4 = var3.length;
// 遍历执行ServletContextInitializer#onStartup
for(int var5 = 0; var5 < var4; ++var5) {
ServletContextInitializer initializer = var3[var5];
initializer.onStartup(servletContext);
}
}
- TomcatStarter是ServletContainerInitializer的实现类。 tomcat容器在启动时会调用ServletContainerInitializer#onStartUp方法。
- TomcatStarter这里的ServletContextInitializer[]只有3个实现类。 其中有一个是this.webServer = factory.getWebServer(**new ServletContextInitializer[]{this.getSelfInitializer()}); 中的new **ServletContextInitializer[]{this.getSelfInitializer()}添加进的
- onStartUp方法会回调去执行ServletWebServerApplicationContext的selfInitialize方法
private ServletContextInitializer getSelfInitializer() {
return this::selfInitialize;
}
private void selfInitialize(ServletContext servletContext) throws ServletException {
this.prepareWebApplicationContext(servletContext);
this.registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(this.getBeanFactory(), servletContext);
// 获取ServletContextInitializerBeans
Iterator var2 = this.getServletContextInitializerBeans().iterator();
// 遍历去执行ServletContextInitializer#onStartup方法
while(var2.hasNext()) {
ServletContextInitializer beans = (ServletContextInitializer)var2.next();
beans.onStartup(servletContext);
}
}
// 获取ServletContextInitializerBeans并排序
ServletContextInitializerBeans类
@SafeVarargs
public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class... initializerTypes) {
this.initializerTypes = initializerTypes.length != 0 ? Arrays.asList(initializerTypes) : Collections.singletonList(ServletContextInitializer.class);
this.addServletContextInitializerBeans(beanFactory);
this.addAdaptableBeans(beanFactory);
List<ServletContextInitializer> sortedInitializers = (List)this.initializers.values().stream().flatMap((value) -> {
return value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE);
}).collect(Collectors.toList());
this.sortedList = Collections.unmodifiableList(sortedInitializers);
this.logMappings(this.initializers);
}
ServletContextInitializerBeans 从beanFactory中获取spring容器中所有的ServletContextInitializer实现(filter列表以及servlet都添加进去)
7, 总结
经过上面一系列的初始化, ServletContextInitializer在容器启动时就被成功调用了。
ServletContextInitializer的实现有很多