SpringBoot-启动原理

Spring Boot应用的整个启动流程都封装在SpringApplication.run方法中,其整个流程很长,但本质上就是在Spring容器启动的基础上做了大量的扩展,按照这个思路来看看源码:

项目启动是通过SpringApplication的静态run方法,那么,这个方法里面首先要创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例方法

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        return new SpringApplication(sources).run(args);
    }

SpringApplication实例初始化完成并且完成设置后,就开始执行run方法的逻辑了

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();
        // 1通过SpringFactoriesLoader加载所有的SpringApplicationRunListeners,并调用starting()方法
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            // 2 创建并配置当前应用将要使用的Environment配置文件(profile)和属性(properties)
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
            // 3 SpringBoot应用在启动输出的Banner 图
            Banner printedBanner = printBanner(environment);
            // 4 根据是否是web项目,来创建不同的ApplicationContext容器
            context = createApplicationContext();
            // 5 通过SpringFactoriesLoader创建一系列FailureAnalyzer用于监控(实现FailureAnalyzer接口的class)
            analyzers = new FailureAnalyzers(context);
            // 6 初始化ApplicationContext
            prepareContext(context, environment, listeners, applicationArguments,printedBanner);
            // 7 调用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序
            refreshContext(context);
            // 8 查找当前context中是否注册有CommandLineRunner和ApplicationRunner,如果有则遍历执行它们。
            afterRefresh(context, applicationArguments);
            // 9 执行所有SpringApplicationRunListener的finished()方法。
            listeners.finished(context, null);
            stopWatch.stop();
            return context;
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }

下面来对于上图每一步进行详细的讲解

1. 启动所有SpringApplicationRunListeners

通过SpringFactoriesLoader查找并加载所有的SpringApplicationRunListeners,通过调用starting()方法通知所有的SpringApplicationRunListeners:应用开始启动了。SpringApplicationRunListeners其本质上就是一个事件发布者,它在SpringBoot应用启动的不同时间点发布不同应用事件类型(ApplicationEvent),如果有哪些事件监听者(ApplicationListener)对这些事件感兴趣,则可以接收并且处理。

主要是启动监听器用来监听后面各个阶段的触发的事件。源码如下

public interface SpringApplicationRunListener {
    // 运行run方法时立即调用此方法,可以用户非常早期的初始化工作
    void starting();
    // Environment准备好后,并且ApplicationContext创建之前调用
    void environmentPrepared(ConfigurableEnvironment environment);
    // ApplicationContext创建好后立即调用
    void contextPrepared(ConfigurableApplicationContext context);
    // ApplicationContext加载完成,在refresh之前调用
    void contextLoaded(ConfigurableApplicationContext context);
    // 当run方法结束之前调用
    void finished(ConfigurableApplicationContext context, Throwable exception);
}

2. 配置Environment

创建并配置当前应用将要使用的Environment,Environment用于描述应用程序当前的运行环境,其抽象了两个方面的内容:配置文件(profile)和属性(properties),开发经验丰富的同学对这两个东西一定不会陌生:不同的环境(eg:生产环境、预发布环境)可以使用不同的配置文件,而属性则可以从配置文件、环境变量、命令行参数等来源获取。因此,当Environment准备好后,在整个应用的任何时候,都可以从Environment中获取资源。

  • 判断Environment是否存在,不存在就创建(如果是web项目就创建StandardServletEnvironment,否则创建StandardEnvironment)
  • 配置Environment:配置profile以及properties
  • 调用SpringApplicationRunListener的environmentPrepared()方法,通知事件监听者:应用的Environment已经准备好

3. 输出Banner图

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.6.RELEASE)

4. 根据是否是web项目,来创建不同的ApplicationContext容器

5. 创建一系列FailureAnalyzer

创建流程依然是通过SpringFactoriesLoader获取到所有实现FailureAnalyzer接口的class,然后在创建对应的实例。FailureAnalyzer用于分析故障并提供相关诊断信息。

6. 初始化ApplicationContext

  • 将准备好的Environment设置给ApplicationContext
  • 遍历调用所有的ApplicationContextInitializer的initialize()方法来对已经创建好的ApplicationContext进行进一步的处理
  • 调用SpringApplicationRunListener的contextPrepared()方法,通知所有的监听者:ApplicationContext已经准备完毕
  • 将所有的bean加载到容器中
  • 调用SpringApplicationRunListener的contextLoaded()方法,通知所有的监听者:ApplicationContext已经装载完毕

7 调用ApplicationContext的refresh()方法

调用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序,主要获取到所有的BeanFactoryPostProcessor来对容器做一些额外的操作。BeanFactoryPostProcessor允许我们在容器实例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做一些额外的操作

// 摘自refresh()方法中一句代码
invokeBeanFactoryPostProcessors(beanFactory);
// 其实现类
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    ......
}

8.查找当前context中是否注册有CommandLineRunner和ApplicationRunner,如果有则遍历执行它们。

9.执行所有SpringApplicationRunListener的finished()方法。

这就是Spring Boot的整个启动流程,其核心就是在Spring容器初始化并启动的基础上加入各种扩展点,这些扩展点包括:ApplicationContextInitializer、ApplicationListener以及各种BeanFactoryPostProcessor等等

你可能感兴趣的:(SpringBoot-启动原理)