Spring Boot应用启动源码分析

125 阅读1分钟

这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

前言

SpringBoot启动流程主要分为两步, 我们可以结合源码来看看整体的启动流程

  1. 初始化一个SpringApplication对象。
  2. 执行该对象的run方法。

SpringApplication初始化流程

SpringApplication的初始化流程,SpringApplication的构造方法.

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   // 判断是否是Web项目
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   // 找到入口类
   this.mainApplicationClass = deduceMainApplicationClass();
}

初始化流程中最重要的就是通过SpringFactoriesLoader找到 spring.factories文件中配置的 ApplicationContextInitializer和 ApplicationListener两个接口的实现类名称,以便后期构造相应的实例。

Spring Boot启动流程

我们从SpringBoot的Run方法开始看。

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
    ConfigurableApplicationContext context = null;
    this.configureHeadlessProperty();
    // 1. 通过SpringFactoriesLoader查找并加载所有的 SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);

    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 2. 创建并配置当前应用将要使用的 Environment
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        this.configureIgnoreBeanInfo(environment);
        // 3. SpringBoot应用在启动时会输出Spring的LOGO
        Banner printedBanner = this.printBanner(environment);
        // 4. 根据是否是web项目,来创建不同的ApplicationContext容器。
        context = this.createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        
        // 5. 初始化ApplicationContext
        this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        // 6. 刷新容器
        this.refreshContext(context);
        this.afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
        }

        listeners.started(context);
        this.callRunners(context, applicationArguments);
    } catch (Throwable var10) {
        this.handleRunFailure(context, var10, listeners);
        throw new IllegalStateException(var10);
    }

    try {
        listeners.running(context);
        return context;
    } catch (Throwable var9) {
        this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
        throw new IllegalStateException(var9);
    }
}