文章目录
基于版本2.0.5.RELEASE
前言
ServletContainerInitializer(传递ServletContext)—>WebApplicationInitializer(创建SpringApplication)—>ApplicationContextInitializer(为spring上下文设置ServletContext属性)—>ServletContextInitializer(ServletContext设置DispatcherServlet)
一、tomcat启动过程
在web容器启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filtes等,servlet规范中通过ServletContainerInitializer实现此功能。每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类,那么,当web容器启动时就会运行这个初始化器做一些组件内的初始化工作。 spring-web模块下就有一个javax.servlet.ServletContainerInitializer文件,文件里内容为 **org.springframework.web.SpringServletContainerInitializer**引用自https://blog.csdn.net/lolichan/article/details/84920534
二、SpringServletContainerInitializer类
类上方的HandlersType注解内容类会被tomcat扫描到实现类并作为参数放入onStartup方法,最终调用WebApplicationInitializer实现类的onStartup方法
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
// 调用下方SpringBootServletInitializer的onStartup方法
initializer.onStartup(servletContext);
}
}
}
三、启动类继承SpringBootServletInitializer
SpringBootServletInitializer是WebApplicationInitializer的实现类,所以会被调用onStartup方法,最终为spring上下文设置一个ServletContext
public void onStartup(ServletContext servletContext) throws ServletException {
// Logger initialization is deferred in case an ordered
// LogServletContextInitializer is being used
this.logger = LogFactory.getLog(getClass());
// 设置上下文AnnotationConfigServletWebServerApplicationContext.class
WebApplicationContext rootAppContext = createRootApplicationContext(
servletContext);
... //
}
protected WebApplicationContext createRootApplicationContext(
ServletContext servletContext) {
SpringApplicationBuilder builder = createSpringApplicationBuilder();
builder.main(getClass());
ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
if (parent != null) {
this.logger.info("Root context already created (using as parent).");
servletContext.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
builder.initializers(new ParentContextApplicationContextInitializer(parent));
}
// 为builder即将构建的SpringApplication对象赋予此属性
builder.initializers(
new ServletContextApplicationContextInitializer(servletContext));
builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
builder = configure(builder);
builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));
SpringApplication application = builder.build();
if (application.getAllSources().isEmpty() && AnnotationUtils
.findAnnotation(getClass(), Configuration.class) != null) {
application.addPrimarySources(Collections.singleton(getClass()));
}
Assert.state(!application.getAllSources().isEmpty(),
"No SpringApplication sources have been defined. Either override the "
+ "configure method or add an @Configuration annotation");
// Ensure error pages are registered
if (this.registerErrorPageFilter) {
application.addPrimarySources(
Collections.singleton(ErrorPageFilterConfiguration.class));
}
// SpringApplication开始运行
return run(application);
}
SpringApplication
public ConfigurableApplicationContext run(String... args) {
... //
// 这一步准备执行已经初始化好的ApplicationContextInitializers实现类
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
... //
}
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
// 执行已经初始化好的ApplicationContextInitializers实现类
applyInitializers(context);
... //
}
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
// 其中ServletContextApplicationContextInitializer负责为
//ApplicationContext设置一个ServletContext上下文,在refresh方法执行到onRefresh时,
//因为上下文已经有了ServletContext上下文,所以不会创建内置tomcat启动
initializer.initialize(context);
}
}
四、ServletWebServerApplicationContext
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
如下,因为上下文已经有了ServletContext上下文,所以不会创建内置tomcat启动
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
// servletContext 不为null,所以不会走这里
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
// 为ServletContext设置一个DispatcherServlet
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
}
private ServletContextInitializer getSelfInitializer() {
return this::selfInitialize;
}
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
// ServletContextInitializer是在解析主启动类@Import注解时,读取spring.factories中的
// DispatcherServletAutoConfiguration类导入的DispatcherServletRegistrationBean类,
// DispatcherServletRegistrationBean间接实现了ServletContextInitializer接口
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}