在学习Sprioingboot的启动原理之后,虽然知道了Springboot应用的启动流程,但很好奇Springboot是如何启动内嵌的Tomcat服务,因此这一章继续探究Springboot的源码。
在之前的文章中说过Springboot应用的启动实际上是执行了SpringApplication的run方法,在run方法中主要有两个方法与Tomcat服务的启动有关,如下所示:
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
// 根据webApplicationType创建初始上下文
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
this.handleRunFailure(context, var12, listeners);
throw new IllegalStateException(var12);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
return context;
} catch (Throwable var11) {
this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var11);
}
}
第一个createApplicationContext(),作用是创建初始上下文的方法,进入createApplicationContext()方法的源码:
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
发现createApplicationContext()是根据webApplicationType利用应用上下文工厂来创建初始应用上下文对象,进入create()方法中,发现ApplicationContextFactory是一个接口,实现该create方法的类有三个:
1. DefaultApplicationContextFactory类
2. AnnotationConfigReactiveWebServerApplicationContext的内部类Factory,创建的是AnnotationConfigReactiveWebServerApplicationContext对象
3.AnnotationConfigServletWebServerApplicationContext的内部类Factory,创建的是AnnotationConfigServletWebServerApplicationContext对象
DefaultApplicationContextFactory中的create方法如下
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
try {
return (ConfigurableApplicationContext)this.getFromSpringFactories(webApplicationType, ApplicationContextFactory::create, AnnotationConfigApplicationContext::new);
} catch (Exception var3) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var3);
}
}
该类中的create方法是调用了getFromSpringFactory()方法:
private <T> T getFromSpringFactories(WebApplicationType webApplicationType, BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult) {
Iterator var4 = SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class, this.getClass().getClassLoader()).iterator();
Object result;
do {
if (!var4.hasNext()) {
return defaultResult != null ? defaultResult.get() : null;
}
ApplicationContextFactory candidate = (ApplicationContextFactory)var4.next();
result = action.apply(candidate, webApplicationType);
} while(result == null);
return result;
}
getFromSpringFactory()方法有三个参数,第一个是webApplicationType,也就是应用类型,第二个参数是一种函数式接口类型的对象,从上面的create方法可以看出传入的ApplicationContextFactory的create函数,实际执行的是该方法中candidate对象的create函数
AnnotationConfigReactiveWebServerApplicationContext.Factory中的Create方法:
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return webApplicationType != WebApplicationType.REACTIVE ? null : new AnnotationConfigReactiveWebServerApplicationContext();
}
AnnotationConfigServletWebServerApplicationContext.Factory中的Create方法:
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return webApplicationType != WebApplicationType.SERVLET ? null : new AnnotationConfigServletWebServerApplicationContext();
}
在实际执行的时候AnnotationConfigReactiveWebServerApplicationContext.Factory和AnnotationConfigServletWebServerApplicationContext.Factory中的create方法都会被执行如果哪一个返回的结果不为null,则会退出循环。
知道了Spring是如何根据WebApplicationType来创建对应的初始上下文对象,下面来看一看刷新上下文对象的方法:
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
this.refresh(context);
}
在这里面主要是利用refresh方法来刷新上述创建好的上下文对象,而这个refresh方法最终还是调用了ConfigurableApplicationContext对象的refresh方法,也就是上述创建的初始上下文中的refresh方法。
实现ConfigurableApplicationContext接口refresh方法的类有三个
1.AbstractApplicationContext抽象类
2.ReactiveWebServerApplicationContext
3.ServletWebServerApplicationContext
而ReactiveWebServerApplicationContext是AnnotationConfigReactiveWebServerApplicationContext的父类,ServletWebServerApplicationContext是AnnotationConfigServletWebServerApplicationContext的父类,一般我们创建的应用类型都为Servlet类型,因此现在只看ServletWebServerApplicationContext中的方法在ServletWebServerApplicationContext的OnRefresh方法中有一个createWebServer()函数:
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
ServletWebServerFactory factory = this.getWebServerFactory();
createWebServer.tag("factory", factory.getClass().toString());
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
createWebServer.end();
this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var5) {
throw new ApplicationContextException("Cannot initialize servlet context", var5);
}
}
this.initPropertySources();
}
在createWebServer()函数中有一个getWebServerFactory()的函数用于创建ServletWebServerFactory对象,这是一个创建servletWebServer的工厂,然后调用工厂对象的getWebServer()方法来创建一个webServer对象
实现getWebServer()方法的类有三个:
1.JettyServletWebServerFactory
2.TomcatServletWebServerFactory
3.UndertowServletWebServerFactory
其中TomcatServletWebServerFactory就是用于创建Tomcat服务的。
由于已经到晚上了,明天还要起来搬砖,今天就写到这儿,明天继续探索TomcatServletWebServerFactory创建Tomcat服务后,Tomcat服务是如何启动的。