SpringBoot 启动分析(二)–启动主流程

1. initialize 方法

SpringApplication 的构造函数只调用了 initialize 方法:

private void initialize(Object[] sources) {
    if (sources != null && sources.length > 0) {
        // 把应用指定的配置类加入配置扫描的启动来源
        this.sources.addAll(Arrays.asList(sources));
    }

    // 判断应用是否是 web 应用,主要用于决定采用哪种具体的上下文实现
    this.webEnvironment = deduceWebEnvironment();

    // 利用定制的 SPI 实现 SpringFactoriesLoader 加载 ApplicationContextInitializer 的所有实现并设置到 initializers 属性
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

    // 利用定制的 SPI 实现 SpringFactoriesLoader 加载 ApplicationListener 的所有实现并设置到 listeners 属性
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

    // 找出启动类:线程栈上 main 方法所处的类
    this.mainApplicationClass = deduceMainApplicationClass();
}

该方法的逻辑主要如下:

  1. 把启动类加入 sources 属性。
  2. 判断是否是 web 应用并设置到 webEnvironment 属性。
  3. 加载所有的 ApplicationContextInitializer 并设置到 initializers 属性。
  4. 加载所有的 ApplicationListener 并设置到 listeners 属性。
  5. 找出 main 类设置到 mainApplicationClass。

2. run 方法

public ConfigurableApplicationContext run(String... args) {
    // StopWatch 主要用来统计应用的启动时间
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    FailureAnalyzers analyzers = null;

    // 配置 AWT 的 headless 属性
    configureHeadlessProperty();

    // 初始化事件广播器,用于广播事件
    SpringApplicationRunListeners listeners = getRunListeners(args);

    // 触发 SpringApplicationRunListener.starting 方法
    // 向 ApplicationListener 广播 ApplicationStartedEvent 事件
    listeners.starting();
    try {
        // 封装命令行参数,后面会注册到上下文里
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

        // 创建并准备 Environment
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

        // 打印 Banner
        Banner printedBanner = printBanner(environment);

        // 创建 ApplicationContext
        context = createApplicationContext();

        // 创建失败分析器
        analyzers = new FailureAnalyzers(context);

        // 
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);

        // 刷新上下文,加载所有的Bean定义并实例化非延迟加载的单例Bean
        refreshContext(context);

        // 获取所有的 ApplicationRunner 和 CommandLineRunner 并执行其回调
        afterRefresh(context, applicationArguments);

        // 广播 ApplicationReadyEvent或ApplicationFailedEvent事件
        listeners.finished(context, null);

        // 终止计时
        stopWatch.stop();

        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        return context;
    } catch (Throwable ex) {
        handleRunFailure(context, listeners, analyzers, ex);
        throw new IllegalStateException(ex);
    }
}

run 方法的核心逻辑:

  1. 创建 StopWatch 用于记录启动耗时;
  2. 创建并准备 Enviroment。加载所有的配置文件和处理 Profile 。
  3. 创建并准备 ApplicationContext ,把 ConfigurationClassPostProcessor 注册到上下文底层的 BeanFacotry
  4. 刷新 ApplicationContext。
  5. 获取所有的 ApplicationRunnerCommandLineRunner 并执行其回调。
  6. 广播 ApplicationReadyEvent或ApplicationFailedEvent事件。

这个流程非常简单,不涉及具体的配置文件解析、加载,bean 定义扫描、解析、加载、实例化 bean 等。就是 SpringBoot 特有的流程,比如打印 Banner、回调 Runner 方法,中间适时广播事件。


欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据