在学习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服务是如何启动的。