SpringBoot启动流程分析2--run方法

发布时间:2024年01月05日

SpringBoot启动流程分析2–run方法

一、概述

源码基于SpringBoot 2.7.xx版本

1.1 简介

SpringBoot启动流程大致分为两个阶段,第一个阶段是SpringApplication 实例化,第二个阶段为执行 run
方法,本章讲解第二阶段,第二阶段内容较多,接下来分篇讲解

  1. 初始化引导上下文–bootStrapContext
  2. 创建应用上下文环境–ConfigurableEnvironment
  3. 创建应用上下文–createApplicationContext
  4. 准备应用上下文–prepareContext
  5. 刷新应用上下文–refreshContext
  6. 刷新应用上下文后的扩展接口–afterRefresh(空方法)
  7. 调用ApplicationRunner和CommandLineRunner对应的run方法

SpringApplication的启动流程各时期发出的Event事件:

  • ApplicationStartingEvent(1.初始化引导上下文后,发布应用启动事件)
  • ApplicationEnvironmentPreparedEvent(2.创建应用上下文环境时,发布应用环境已准备完毕事件)
  • ApplicationContextInitializedEvent(4.准备应用上下文时,发布应用上下文已初始化事件)
  • ApplicationPreparedEvent(4.准备应用上下文时,发布应用上下文已准备完毕事件)
  • ApplicationStartedEvent(6.刷新应用上下文后的扩展接口后,发布应用上下文已启动事件)
  • ApplicationReadyEvent(7.调用ApplicationRunner和CommandLineRunner对应的run方法后,发布应用上下文准备就绪事件)
  • ApplicationFailedEvent(如果2-7步中出现异常,则发布应用上下文启动失败事件)

在这里插入图片描述

1.2 名词解释

  • 应用上下文–ApplicationContext
    可以理解成IoC容器的高级表现形式,应用上下文确实是在IoC容器的基础上丰富了一些高级功能。
  • IoC容器–DefaultListableBeanFactory
    应用上下文有一个属性beanFactory,就是IoC容器–DefaultListableBeanFactory,他们之间是持有和扩展的关系。

二、详解

2.1 SpringApplication的run方法

public class SpringApplication {

    public ConfigurableApplicationContext run(String... args) {
        // 开启时间监控
        long startTime = System.nanoTime();
        // 1. 初始化引导上下文--bootStrapContext
        DefaultBootstrapContext bootstrapContext = createBootstrapContext();
        ConfigurableApplicationContext context = null;
        // 这个是设置系统参数:java.awt.headless
        configureHeadlessProperty();
        // 获取监听器--SpringApplicationRunListeners
        SpringApplicationRunListeners listeners = getRunListeners(args);
        // 触发 ApplicationStartingEvent事件,LoggingApplicationListener 监听器进行监听
        listeners.starting(bootstrapContext, this.mainApplicationClass);
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 2. 创建应用上下文环境--ConfigurableEnvironment
            ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            configureIgnoreBeanInfo(environment);
            // 这里就是打印图标的地方,默认是会打印Spring,如果你设置了其他图标,那么就打印设置的图标
            Banner printedBanner = printBanner(environment);
            // 3. 创建应用上下文--ConfigurableApplicationContext
            context = createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            // 4. 准备应用上下文--prepareContext
            prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            // 5. 刷新应用上下文--refreshContext
            refreshContext(context);
            // 6. 刷新应用上下文后的扩展接口--afterRefresh(空方法)
            afterRefresh(context, applicationArguments);
            Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
            }
            listeners.started(context, timeTakenToStartup);
            // 7. 调用ApplicationRunner和CommandLineRunner对应的run方法
            callRunners(context, applicationArguments);
        } catch (Throwable ex) {
            handleRunFailure(context, ex, listeners);
            throw new IllegalStateException(ex);
        }
        try {
            Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
            listeners.ready(context, timeTakenToReady);
        } catch (Throwable ex) {
            handleRunFailure(context, ex, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }
}

2.2 初始化引导上下文–bootStrapContext

public class SpringApplication {

    private DefaultBootstrapContext createBootstrapContext() {
        DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
        this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
        return bootstrapContext;
    }
}

2.3 初始化运行监听器–SpringApplicationRunListener

SpringApplicationRunListener用来在整个启动流程中接收不同执行点事件通知的监听者,SpringApplicationRunListener接口规定了SpringBoot的
启动流程,在各个启动流程广播相应的事件。

public class SpringApplication {
    /**
     * 获取所有运行监听器
     * @param args
     * @return
     */
    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
        // 实例化classpath下 META-INF/spring.factories中已配置的 SpringApplicationRunListener
        return new SpringApplicationRunListeners(logger,
                getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
                this.applicationStartup);
    }
}

SpringApplicationRunListener:

public interface SpringApplicationRunListener {

    // 初始化引导上下文后,发布应用启动事件
    default void starting(ConfigurableBootstrapContext bootstrapContext) {
    }

    // 创建应用上下文环境时,发布应用环境已准备完毕事件
    default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
                                     ConfigurableEnvironment environment) {
    }

    // 准备应用上下文时,发布应用上下文已初始化事件
    default void contextPrepared(ConfigurableApplicationContext context) {
    }

    // 准备应用上下文时,发布应用上下文已准备完毕事件
    default void contextLoaded(ConfigurableApplicationContext context) {
    }

    // 刷新应用上下文后的扩展接口后,发布应用上下文已启动事件
    default void started(ConfigurableApplicationContext context, Duration timeTaken) {
        started(context);
    }

    // 调用ApplicationRunner和CommandLineRunner对应的run方法后,发布应用上下文准备就绪事件
    default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        running(context);
    }

    // 如果2-7步中出现异常,则发布应用上下文启动失败事件
    default void failed(ConfigurableApplicationContext context, Throwable exception) {
    }

}

SpringApplicationRunListeners、SpringApplicationRunListener和ApplicationListener的关系:

  1. SpringApplicationRunListener接口规定了SpringBoot的启动流程/生命周期
  2. SpringApplicationRunListeners是SpringApplicationRunListener的封装,SpringApplicationRunListeners中包含
    多个SpringApplicationRunListener,是为了批量执行的封装。
  3. SpringApplicationRunListeners与SpringApplicationRunListener方法相同,
    调用每个启动流程的SpringApplicationRunListener方法,然后广播相应的事件到Spring框架的ApplicationListener。
文章来源:https://blog.csdn.net/fanderboy/article/details/135371530
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。