SpringBoot 2.x 外部servlet容器启动原理
1)创建一个war项目,创建好目录结构(webapp文件夹,web.xml)
2)将嵌入式tomcat指定为provided
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
3)编写一个SpringBootServletInitializer 子类,并重写config方法
public class ServletInitializer extends SpringBootServletInitializer {
//调用父类的 onStartup方法
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Springboot06WebJspApplication.class);
}
}
4)启动服务器
1.原理:
首先启动servlet容器,servlet容器带动springBoot应用启动
servlet3.0定义规则:
1)服务器启动时,会创建当前web应用每一个jar包里的ServletContainerInitializer实例
2)jar包的META-INF/service w文件夹下有一个javax.servlet.ServletContainerInitialize 文件
文件的内容是 ServletContinerInitializer 实现类的全路径
3)@HandlesTypes()
能够在应用启动时加载我们想要加载的类
2.启动流程:
1) 启动tomcat
2) 创建ServletContainerInitializer 实例
- org\springframework\spring-web\5.2.1.RELEASE\spring-web-5.2.1.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer
- 创建 org.springframework.web.SpringServletContainerInitializer 实例
3) SpringServletContainerInitializer 上的 @HandlesType(WebApplicationInitializer.class) 将所有WebApplicationInitializer类型的实例以set集合的形式加载进来,并为其创建实例
4) 每一个WebApplicationInitializer 实例都会调用自己的 onStartup() 方法
- 我们自己创建的 SpringBootServletInitializer 将会被实例化,并执行onStartup 方法
5) SpringBootServletInitializer 实例执行 onStartup方法时 会执行createRootApplicationContext 方法创建容器
WebApplicationContext rootAppContext = createRootApplicationContext(servletContext);
6)createRootApplicationContext创建容器时会执行builder = configure(builder);方法
- 因为子类重写了这个方法,会将springBoot主程序类传入
protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
//因为子类重写了这个方法,会将springBoot主程序类传入
builder = configure(builder);
builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));
//使用bulid 创建一个spring应用
SpringApplication application = builder.build();
//启动springBoot应用
return run(application);
}
//启动spring应用
protected WebApplicationContext run(SpringApplication application) {
return (WebApplicationContext) application.run();
}
7)springBoot应用启动并创建IOC容器
- refreshContext(context);刷新IOC容器
- –>createWebServer();
- –>ServletWebServerFactory factory = getWebServerFactory();
–>this.webServer = factory.getWebServer(getSelfInitializer());
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新IOC容器
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}