/**
* 原理:
* <pre>
* javax.servlet规范提供的机制ServletContainerInitializers(SCIs)
* 在META-INF/services/javax.servlet.ServletContainerInitializer文件中
* 将ServletContainerInitializer实现类写在该文件中,Web容器会自动将这些实现类加载,并调用这些类的onStartup
* 同时,还可以实现类中使用@HandlesTypes(Xxx.class)注解,将Xxx.class的所有子类(接口,实现类,抽象类)通过onStartup传递
* 并且还会将ServletContext上下文传递过来
* </pre>
* <pre>
* 其中,SpringServletContainerInitializer实现了ServletContainerInitializer接口
* 并在spring-web\5.2.2.RELEASE\spring-web-5.2.2.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer注册了该实现类
* 而SpringServletContainerInitializer又使用了HandlesTypes直接,此时,就会将Spring提供的WebApplicationInitializer接口的所有实现类传递,这就与Spring建立了连接
* @HandlesTypes(WebApplicationInitializer.class)
* public class SpringServletContainerInitializer implements ServletContainerInitializer {
*
* }
* </pre>
* 使用步骤:
* <pre>
* 1. 将springboot项目打包成war包
* <packaging>war</packaging>
* 2. 创建类继承SpringBootServletInitializer,可以重写configure方法设置自定义配置
* 3. 将war部署到Tomcat中,和单独的springmvc项目一样
* </pre>
*/
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) {
List<WebApplicationInitializer> initializers = new LinkedList<>();
// 所有WebApplicationInitializer的实现类
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
// 创建这些类的实例对象
initializers.add((WebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
}
}
// 如果不存在WebApplicationInitializer的实现类,就不需要处理
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
// 如果存在WebApplicationInitializer的实现类
// 排序
AnnotationAwareOrderComparator.sort(initializers);
// 回调每一个WebApplicationInitializer的onStartup方法
for (WebApplicationInitializer initializer : initializers) {
// SpringBootServletInitializer initializer;
// 这里就包含了SpringBootServletInitializer,SpringBoot的初始化器
initializer.onStartup(servletContext);
}
}
}
class SpringBootServletInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
WebApplicationContext rootAppContext = createRootApplicationContext(servletContext);
if (rootAppContext != null) {
servletContext.addListener(new ContextLoaderListener(rootAppContext) {
@Override
public void contextInitialized(ServletContextEvent event) {
// 无操作,因为应用程序上下文已经初始化
}
});
}
}
// 创建Spring容器
protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
// 创建构建者模式创建SpringApplication
SpringApplicationBuilder builder = this.createSpringApplicationBuilder() {
return new SpringApplicationBuilder();
{
// 直接创建SpringApplication对象
this.application = new SpringApplication(sources);
}
}
// 设置main运行的类
builder.main(getClass()) {
this.application.setMainApplicationClass(mainApplicationClass);
}
// 查看是否创建过了容器,创建了则不再创建
// WebApplicationContext.class.getName() + ".ROOT";
ApplicationContext parent = getExistingRootWebApplicationContext(servletContext) {
Object context = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
if (context instanceof ApplicationContext) {
return (ApplicationContext) context;
}
return null;
}
if (parent != null) {
// 重置Context对象
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
// 添加一个初始化器,该类就是为创建的Context设置父容器
builder.initializers(new ParentContextApplicationContextInitializer(parent));
}
// 添加一个初始化器,就是将创建的上下文重新设置到servletContext
// 上面几行代码就是在判断之前是否存在Context对象,如果存在,将之前的Context对象作为即将创建Context的父容器
builder.initializers(new ServletContextApplicationContextInitializer(servletContext));
// 设置要创建的上下文对象类型
builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
// 空实现,对builder进行自定义配置
builder = this.configure(builder);
// 添加ApplicationListener监听器,该类就是将ServletContext的相关属性设置到环境对象中
builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));
// 创建SpringApplication对象
SpringApplication application = builder.build() {
// 将当前设置的配置类设置为主要的配置类
this.application.addPrimarySources(this.sources);
return this.application;
}
// 如果没有设置解析的配置类,但是当前类中存在@Configuration注解
// 将当前类设置为需要解析的配置类
if (application.getAllSources().isEmpty() && MergedAnnotations.from(getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) {
application.addPrimarySources(Collections.singleton(getClass()));
}
// 如果需要注册错误页面的过滤器
if (this.registerErrorPageFilter) {
// 添加一个配置类,该类就是注册org.springframework.boot.web.servlet.support.ErrorPageFilter
application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
}
// 调用SpringBootApplication.run方法,详细的请看文章SpringBoot运行原理
return application.run();
}
}
// 这是自己写的类,继承了SpringBootServletInitializer,因此也会执行
@SpringBootApplication
public class App extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
builder.sources(App.class);
return super.configure(builder);
}
}
01-09
1273
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交