外置Tomcat时,在Tomcat启动时会去找spring-web中META-INF/service/javax.servlet.ServletContainerInitializer中配置的SpringServletContainerInitializer,然后运行其中的onStartup()方法;这是Servlet3开始支持的一种方式。
而SpringBoot是由SpringApplication的run方法作为入口,不会像上面那样去找配置。而是创建了一个类TomcatStarter
class TomcatStarter implements ServletContainerInitializer
所以Tomcat启动时会调用TomcatStarter的onStartup()方法
@Override
public void onStartup(Set<Class<?>> classes, ServletContext servletContext)
throws ServletException {
try {
for (ServletContextInitializer initializer : this.initializers) {
initializer.onStartup(servletContext);
}
}
}
而initializer 在前面已经初始化了,比较难理解的是这里利用了lambda表达式以及匿名内部类,在ServletWebServerApplicationContext中
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
//这里调用下面的方法getSelfInitializer()返回一个ServletContextInitializer实例
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
}
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
return this::selfInitialize;
}
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
beanFactory);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
getServletContext());
existingScopes.restore();
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
getServletContext());
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
以上代码相当于下面的代码
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
return (servletContext) -> {
prepareWebApplicationContext(servletContext);
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
beanFactory);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
getServletContext());
existingScopes.restore();
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
getServletContext());
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
通过这里就知道Spring Boot中Servlet,Filter是如何注册到容器中的ServletContext了

SpringBoot的启动不同于外置Tomcat通过SpringServletContainerInitializer的方式,它使用TomcatStarter并在ServletWebServerApplicationContext中利用lambda表达式和匿名内部类进行Servlet、Filter的注册。
1493

被折叠的 条评论
为什么被折叠?



