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

总结摘要
SpringBoot启动流程03

printBanner

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// org.springframework.boot.SpringApplication#run(java.lang.String...)
--> 打印横幅 Banner。`printBanner(environment)`。
    --|> `org.springframework.boot.SpringApplication#printBanner`
    --> 当前`this.bannerMode`值为`Mode.CONSOLE`。
    --> `new SpringApplicationBannerPrinter`
        --> `new SpringBootBanner()`
    --> 如果`this.bannerMode`值为`Mode.LOG`
        --|> bannerPrinter.print(environment, this.mainApplicationClass, logger);
        --|> 详情参见下文值为`Mode.CONSOLE`的场景
    --> 如果`this.bannerMode`值为`Mode.CONSOLE`
        --|> bannerPrinter.print(environment, this.mainApplicationClass, System.out);
        --> org.springframework.boot.SpringApplicationBannerPrinter#print(org.springframework.core.env.Environment, java.lang.Class<?>, java.io.PrintStream)
            --> 获取`Banner`。`org.springframework.boot.SpringApplicationBannerPrinter#getBanner`
                --> 获取`ImageBanner`,`org.springframework.boot.SpringApplicationBannerPrinter#getImageBanner`
                    --> 查询属性`spring.banner.image.location`,如果存在则加载并返回
                    -->  classpath 查询文件`banner.``SpringApplicationBannerPrinter#IMAGE_EXTENSION`后缀拼接
                    --> 封装为`ImageBanner`返回
                --> 获取`TextBanner`,`org.springframework.boot.SpringApplicationBannerPrinter#getTextBanner`
                    --|> 查询属性`spring.banner.location`,如果存在则加载并返回
                    --|>  classpath 查询文件`banner.txt`
                    --> 封装为`ResourceBanner`返回
                --> 如果前两个步骤未获取到 Banner即不存在用户自定义 Banner则使用默认`DEFAULT_BANNER`(`SpringBootBanner`)。
            --> 打印`Banner`。调用接口方法`org.springframework.boot.Banner#printBanner`。
            --> 返回`new PrintedBanner(banner, sourceClass);`。

createApplicationContext

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// org.springframework.boot.SpringApplication#run(java.lang.String...)
--> 创建`ApplicationContext`。`createApplicationContext();`。
    --|> `org.springframework.boot.SpringApplication#createApplicationContext`。
    --> `this.applicationContextFactory`默认为`ApplicationContextFactory.DEFAULT`(`new DefaultApplicationContextFactory()`)。
    --> 调用接口方法`org.springframework.boot.ApplicationContextFactory#create`。
        --|> 实际调用`org.springframework.boot.DefaultApplicationContextFactory#create`。
        --> 加载合适的自动配置类`ApplicationContextFactory`的实现类
            --|> `getFromSpringFactories(webApplicationType, ApplicationContextFactory::create, AnnotationConfigApplicationContext::new);`
            --|> org.springframework.boot.DefaultApplicationContextFactory#getFromSpringFactories
            --> `SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class`
                --> SpringBoot 自动配置有2个实现
                --> AnnotationConfigReactiveWebServerApplicationContext.Factory
                --> AnnotationConfigServletWebServerApplicationContext.Factory
            --> `AnnotationConfigServletWebServerApplicationContext`满足条件调用其无参数构造方法(`AnnotationConfigApplicationContext::new`)实例化
 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
// AnnotationConfigServletWebServerApplicationContext 实例化详情
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext#AnnotationConfigServletWebServerApplicationContext()
--> org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry)
    --> org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.Environment)
        --> org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
            --> 注册组件。`org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)`
                --> 注册 2 个工具类
                    --|> AnnotationAwareOrderComparator.INSTANCE
                    --|> new ContextAnnotationAutowireCandidateResolver()
                --> 注册 6  bean 定义
                    --|> ConfigurationClassPostProcessor.class
                    --|> AutowiredAnnotationBeanPostProcessor.class
                    --|> CommonAnnotationBeanPostProcessor.class
                    --|> PersistenceAnnotationBeanPostProcessor.class
                    --|> EventListenerMethodProcessor.class
                    --|> DefaultEventListenerFactory.class
--> org.springframework.context.annotation.ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner(org.springframework.beans.factory.support.BeanDefinitionRegistry)
    --> `this(registry, true);`
        --|> org.springframework.context.annotation.ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner(org.springframework.beans.factory.support.BeanDefinitionRegistry, boolean)
        --> org.springframework.context.annotation.ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner(org.springframework.beans.factory.support.BeanDefinitionRegistry, boolean, org.springframework.core.env.Environment)
            --> org.springframework.context.annotation.ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner(org.springframework.beans.factory.support.BeanDefinitionRegistry, boolean, org.springframework.core.env.Environment, org.springframework.core.io.ResourceLoader)
                --> 入参`useDefaultFilters`值为 true配置`includeFilters`。
                    --|> org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#registerDefaultFilters
                    --> 默认规则为由注解`Component.class`修饰
                    --> 如果 classpath 存在`javax.annotation.ManagedBean``javax.inject.Named`, 则也作为`includeFilters`条件
                --> 配置 environment 作为属性
                --> 配置 resourceLoader 属性
                    --> 可能使用了 PathMatchingResourcePatternResolver待确认
                    --> `this.componentsIndex`在此处加载通常未使用

prepareContext

 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
// org.springframework.boot.SpringApplication#run(java.lang.String...)
--> 准备`ConfigurableApplicationContext`。
    --|> `prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);`
    --|> `org.springframework.boot.SpringApplication#prepareContext`
    --> 配置属性`environment`。
    --> 配置属性。`postProcessApplicationContext`
        --|> org.springframework.boot.SpringApplication#postProcessApplicationContext
        --> 如果 SpringApplication `this.beanNameGenerator`存在则注入到 context此时不存在无法注入
        --> 如果 SpringApplication `this.resourceLoader`存在则注入到 context此时不存在无法注入
        -->  environment  conversionService 注入到 context  beanFactory 
    --> 应用`ApplicationContextInitializer`。`applyInitializers`。
        --|> org.springframework.boot.SpringApplication#applyInitializers
        --> 获取 ApplicationContextInitializer。`org.springframework.boot.SpringApplication#getInitializers`
            --|> 默认有7个`SpringApplication`的构造方法中初始化的
            --|> 有序排列如下
            --> DelegatingApplicationContextInitializer 
                --|> 调用委托类的`initialize`方法委托类来源于配置参数`context.initializer.classes`。
                --|> 默认未配置该参数因此无有效逻辑
            --> SharedMetadataReaderFactoryContextInitializer
                --|> 添加`CachingMetadataReaderFactoryPostProcessor`。
            --> ContextIdApplicationContextInitializer
                --|> 注册`ContextId`作为 context  id
                --|>  id 名称来源于配置参数`spring.application.name`,默认名称为`application`。
            --> ConfigurationWarningsApplicationContextInitializer
                --|> 注册`ConfigurationWarningsPostProcessor`。
                --|> 作用大意是检查禁止`@ComponentScan`配置扫描`org.springframework``org`
            --> RSocketPortInfoApplicationContextInitializer
                --|> 添加1个`ApplicationListener`实现类`RSocketPortInfoApplicationContextInitializer.Listener`。
                --|> 作用是将`server.ports`属性配置到 environment 
                --|> 当前未使用 RSocket
            --> ServerPortInfoApplicationContextInitializer
                --|> 添加1个`ApplicationListener`实现类`ServerPortInfoApplicationContextInitializer`,即添加本身
                --|> 配置端口号 port 属性默认属性名称为`local.server.port`,中间`server`来源于`ServerNamespace`。
            --> ConditionEvaluationReportLoggingListener 
                --|> 添加1个`ApplicationListener`实现类`ConditionEvaluationReportListener`。
                --|> 打印部分日志
    --> 发布`ApplicationContextInitializedEvent`事件
        --|> `listeners.contextPrepared(context);`
        --|> 默认无该事件的响应
    --> 关闭`bootstrapContext`。`bootstrapContext.close(context);`。
    --> 

ApplicationStartedEvent

该事件实际无响应。

ApplicationReadyEvent

该事件有3个响应,其中BackgroundPreinitializer真实响应,其它2个可能默认未使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
BackgroundPreinitializer
ApplicationListener to trigger early initialization in a background thread of time-consuming tasks.
一个 `ApplicationListener`,用于在后台线程中触发耗时任务的早期初始化
--> org.springframework.boot.autoconfigure.BackgroundPreinitializer#onApplicationEvent
    --> `preinitializationComplete.await();`
        --|> 等待异步线程执行完成

SpringApplicationAdminMXBeanRegistrar
Register a SpringApplicationAdminMXBean implementation to the platform MBeanServer.
在平台的`MBeanServer`中注册一个`SpringApplicationAdminMXBean`实现
--> org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar#onApplicationEvent
    --> org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar#onApplicationReadyEvent
        --> 设置变量`SpringApplicationAdminMXBeanRegistrar#ready` true

ApplicationPidFileWriter
An ApplicationListener that saves application PID into file. This application listener will be triggered exactly once per JVM, and the file name can be overridden at runtime with a System property or environment variable named "PIDFILE" (or "pidfile") or using a spring.pid.file property in the Spring Environment.
一个 ApplicationListener用于将应用程序的 PID 保存到文件中此应用程序监听器将在每个 JVM 中恰好触发一次文件名可以通过名为 PIDFILE pidfile的系统属性或环境变量或者通过 Spring 环境中的`spring.pid.file`属性在运行时覆盖
--> org.springframework.boot.context.ApplicationPidFileWriter#onApplicationEvent
    --> 

其它事件 ServletWebServerInitializedEvent

1
// 发布时机

END