Spring源码-SpringBoot-启动流程-01

总结摘要
SpringBoot启动流程01

前言

SpringBoot 的入口方法如下,入口方法有2个特征

  1. 声明注解@SpringBootApplication
  2. main方法中调用方法org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String...)
1
2
3
4
5
6
7
8
// 如下是简洁版本。
// 通常用户会根据业务需求额外声明一些注解,例如`@PropertySource`,`@ComponentScan`等,参见其它篇章。
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

SpringApplication 构造方法

源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    // primarySources 默认为声明注解`@SpringBootApplication`(通常也是调用`SpringApplication#run`的`main`方法)的所在类。
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 从 classpath 探测 web application type,通常为`org.springframework.boot.WebApplicationType#SERVLET`。
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 从"META-INF/ spring.factories"探测`BootstrapRegistryInitializer.class`的实现类。
    this.bootstrapRegistryInitializers = new ArrayList<>(
            getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    // 从"META-INF/ spring.factories"探测`ApplicationContextInitializer.class`的实现类。
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 从"META-INF/ spring.factories"探测`ApplicationListener.class`的实现类。
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 探测 main 方法所在的类,具体方式是获取堆栈信息后过滤 main 方法。
    this.mainApplicationClass = deduceMainApplicationClass();
}

自动配置类 ApplicationContextInitializer 和 ApplicationListener 介绍

SpringBoot 自动配置ApplicationContextInitializer实现,详情如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
--> getSpringFactoriesInstances(ApplicationContextInitializer.class)
    --|> 默认 8 推测当前不重要
--> getSpringFactoriesInstances(ApplicationListener.class)
    --|> 默认 8 名称列表如下详情参见后文):
        --> org.springframework.boot.ClearCachesApplicationListener
        --> org.springframework.boot.builder.ParentContextCloserApplicationListener
        --> org.springframework.boot.context.FileEncodingApplicationListener
        --> org.springframework.boot.context.config.AnsiOutputApplicationListener
        --> org.springframework.boot.context.config.DelegatingApplicationListener
        --> org.springframework.boot.context.logging.LoggingApplicationListener
        --> org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
        --> org.springframework.boot.autoconfigure.BackgroundPreinitializer
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// ApplicationListener.class
--> org.springframework.boot.ClearCachesApplicationListener
ApplicationListener to cleanup caches once the context is loaded.
清理上下文加载完成后缓存的应用程序监听器

--> org.springframework.boot.builder.ParentContextCloserApplicationListener
Listener that closes the application context if its parent is closed.
如果父上下文关闭则关闭应用程序上下文的监听器

--> org.springframework.boot.context.FileEncodingApplicationListener
An ApplicationListener that halts application startup if the system file encoding does not match an expected value set in the environment. By default has no effect, but if you set spring. mandatory_file_encoding (or some camelCase or UPPERCASE variant of that) to the name of a character encoding (e. g. "UTF-8") then this initializer throws an exception when the file. encoding System property does not equal it.
如果系统文件编码与环境设置的预期值不匹配则会阻止应用程序启动的`ApplicationListener`。默认情况下没有效果但如果您设置`spring.mandatory_file_encoding`(或其某些驼峰式或大写变体为字符编码的名称例如UTF-8”),则当`file.encoding`系统属性与其不相等时此初始化器会抛出异常

--> org.springframework.boot.context.config.AnsiOutputApplicationListener
An ApplicationListener that configures AnsiOutput depending on the value of the property `spring.output.ansi.enabled`.
根据`spring.output.ansi.enabled`属性的值配置`AnsiOutput``ApplicationListener`。

--> org.springframework.boot.context.config.DelegatingApplicationListener
ApplicationListener that delegates to other listeners that are specified under a context. listener. classes environment property.
委托给在`context.listener.classes`环境属性下指定的其他监听器的`ApplicationListener`。

--> org.springframework.boot.context.logging.LoggingApplicationListener
An ApplicationListener that configures the LoggingSystem. If the environment contains a logging. config property it will be used to bootstrap the logging system, otherwise a default configuration is used
配置`LoggingSystem``ApplicationListener`。如果环境中包含`logging.config`属性则会使用它来引导日志系统否则会使用默认配置

--> org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
SmartApplicationListener used to trigger EnvironmentPostProcessors registered in the spring. factories file.
用于触发在`spring.factories`文件中注册的`EnvironmentPostProcessors``SmartApplicationListener`。

--> org.springframework.boot.autoconfigure.BackgroundPreinitializer
ApplicationListener to trigger early initialization in a background thread of time-consuming tasks.
在后台线程中触发耗时任务的早期初始化的应用程序监听器

SpringApplication#run 入口方法介绍

源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// org.springframework.boot.SpringApplication#run
public ConfigurableApplicationContext run(String... args) {
    long startTime = System.nanoTime();
    // 创建默认 Boot 启动上下文`org.springframework.boot.DefaultBootstrapContext`;
    // 并调用扩展点回调方法`org.springframework.boot.BootstrapRegistryInitializer#initialize`。
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    // 配置 headless,略。
    configureHeadlessProperty();
    // 获取自动配置的`SpringApplicationRunListener.class`实例。
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 发布`ApplicationStartingEvent`事件,有若干个监听器生效。
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
        // 封装 SpringApplication 传递的参数。
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 构建`Environment`,完成了配置文件加载、profile 启用等工作。
        // 发布`ApplicationEnvironmentPreparedEvent`事件。
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        // 配置`spring.beaninfo.ignore`属性,略。
        configureIgnoreBeanInfo(environment);
        // 打印 Banner(横幅),略。
        Banner printedBanner = printBanner(environment);
        // 创建`ConfigurableApplicationContext`,默认创建注解驱动的`AnnotationConfigServletWebServerApplicationContext`。
        context = createApplicationContext();
        // 为 context 配置`ApplicationStartup`。
        context.setApplicationStartup(this.applicationStartup);
        // 配置`ConfigurableApplicationContext`。
        // 先后发布`ApplicationContextInitializedEvent`和`ApplicationPreparedEvent`两个事件。
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        // 刷新 Context,注册和预创建 bean。
        refreshContext(context);
        // 空逻辑,略。
        afterRefresh(context, applicationArguments);
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
        }
        // 发布`ApplicationStartedEvent`事件。
        listeners.started(context, timeTakenToStartup);
        // 调用回调方法,支持`ApplicationRunner`和`CommandLineRunner`两类。
        callRunners(context, applicationArguments);
        }
    catch (Throwable ex) {
        // 异常处理,发布`ApplicationFailedEvent`事件。
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
        // 发布`ApplicationReadyEvent`事件。
        listeners.ready(context, timeTakenToReady);
    }
    catch (Throwable ex) {
        // 异常处理,发布`ApplicationFailedEvent`事件。
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

主流程

部分补充详情

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
org.springframework.boot.SpringApplication#run(java.lang.String...)
--> createBootstrapContext();
    --|> org.springframework.boot.SpringApplication#createBootstrapContext
    --|> 创建默认 Boot 启动上下文`org.springframework.boot.DefaultBootstrapContext`。
    --|> 调用扩展点回调方法`org.springframework.boot.BootstrapRegistryInitializer#initialize`初始化上下文默认无扩展点实例
--> getRunListeners(args);
    --> getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)
    --> 仅1个`SpringApplicationRunListener`,`EventPublishingRunListener`。
--> listeners.starting(bootstrapContext, this.mainApplicationClass);
    --> 发布`ApplicationStartingEvent`。
    --> 生效的listener有3个
        --|> LoggingApplicationListener classpath 存在 logback因此默认生成了`LogbackLoggingSystem`。
        --|> BackgroundPreinitializer无有效逻辑跳过
        --|> DelegatingApplicationListener无有效逻辑跳过
--> new DefaultApplicationArguments(args)
    --> 当前 args 为空跳过
--> 构建`Environment`。
    --|> `prepareEnvironment(listeners, bootstrapContext, applicationArguments);`
    --|> `org.springframework.boot.SpringApplication#prepareContext`
--> createApplicationContext();
    --|> 创建`AnnotationConfigServletWebServerApplicationContext`。

// --> org.springframework.boot.SpringApplication#refreshContext
// --> listeners.started(context, timeTakenToStartup);
// --> org.springframework.boot.SpringApplication#callRunners

END