盘点 SpringBoot Application 主流

首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜

文章合集 : 🎁 juejin.cn/post/694164…

Github : 👉 github.com/black-ant

CASE 备份 : 👉 gitee.com/antblack/ca…

一 . 前言

这一篇来说一说 SpringBoot Application 的主流程.

SpringAppliation 的主流程入口很简单 :

1
2
3
4
5
6
7
8
9
java复制代码@SpringBootApplication
public class BaseApplication {
public static void main(String[] args) {
SpringApplication.run(BaseApplication.class, args);
}
}

1 > 使用 @SpringBootApplication 注解,标明是 Spring Boot 应用。通过它,可以开启自动配置的功能。
2 > main 方法 : 调用 SpringApplication#run(Class<?>... primarySources) 方法,启动 Spring Boot 应用

我们从这个入口一步步看看 , 这个流程里面到底做了什么 , 其中主要涉及这几件事:

  • 创建且启动 listener
  • 通过 args 生成 environment
  • 通过 environment 创建 context
  • 刷新 context
  • 当然 , 还会打印 Banner

流程图

SpringBoot 流程.png

二 . 流程解析

2.1 SpringApplication 核心流程

核心流程主要在SpringApplication.class 中 ,我们从这个流程看看:

SpringApplication 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
java复制代码F- resourceLoader
?- 资源加载器
F- primarySources 
?- 主要的 Java Config 类的数组
F- webApplicationType 
?- 调用 WebApplicationType#deduceFromClasspath() 方法,通过 classpath ,判断 Web 应用类型。
F- listeners 
?- ApplicationListener 数组。
F- mainApplicationClass 
?- 调用 #deduceMainApplicationClass() 方法,获得是调用了哪个 #main(String[] args) 方法


// 提供了三种 ApplicationContext 加载类 , 这个后续会用上
String DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext";
String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";


// 默认Banner 地址 -> "banner.txt"
String BANNER_LOCATION_PROPERTY_VALUE = SpringApplicationBannerPrinter.DEFAULT_BANNER_LOCATION;

SpringApplication run 方法主流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码M1_01- run()
T-> 计时 ,创建 StopWatch 并且启动 , 用于记录启动的时长
-> configureHeadlessProperty() : 配置 headless 属性
?- Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标
?- 该模式下可以创建轻量级组件 , 收集字体等前置工作
- getRunListeners : 获取 SpringApplicationRunListeners ,并且开启监听 listeners.starting()
- 1 创建  ApplicationArguments 对象
- 2 prepareEnvironment 加载属性配置(传入 listener + arguments ) -> M20_01
?- 执行完成后,所有的 environment 的属性都会加载进来 (application.properties等)
- 3 打印banner(printBanner)
- 4 创建Spring 容器(createApplicationContext)
- 准备异常对象(getSpringFactoriesInstances.SpringBootExceptionReporter )
- 5 调用所有初始化类的 initialize 方法(prepareContext) , 初始化Spring 容器
- 6 刷新容器(refreshContext) , 执行 Spring 容器的初始化的后置逻辑(afterRefresh)
T-> 计时完成
- 7 通知 SpringApplicationRunListener , 执行异常处理等收尾

SpringApplication 主流程伪代码

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
java复制代码public ConfigurableApplicationContext run(String... args) throws Exception {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 调用 M1_21 获取 ConfigurableEnvironment
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// PS:M1_01_03
context = createApplicationContext();
// 从 factories 中获取 Exception M1_11
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// M1_35 : 为 Context 添加属性
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// M1_50 : 刷新容器Bean
refreshContext(context);
afterRefresh(context, applicationArguments);
// 计时结束
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);

// 执行 implements ApplicationRunne 对象
callRunners(context, applicationArguments);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}

try {
listeners.running(context);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

2.2 子模块 : Enviroment 处理

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
java复制代码M1_21- prepareEnvironment
- getOrCreateEnvironment -> M21_01
-

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 内部通过 WebApplicationType 生成不同的 Environment (可以set 自己的 Environment) -> M1_23
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 重写此方法以完全控制环境自定义,或者重写上述方法之一以分别对属性源或概要文件进行细粒度控制。 -> M1_24
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 对 configurationProperties 属性进行处理 -> M2_01
ConfigurationPropertySources.attach(environment);
// listener 处理
listeners.environmentPrepared(environment);
// 将 environment 绑定到 SpringApplication
bindToSpringApplication(environment); -> M1_25
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}

M1_23- getOrCreateEnvironment
- 通过 webApplicationType , 创建三种不同的 Environment

// M1_23 伪代码
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}


M1_24- configureEnvironment
- 获取 ApplicationConversionService 的实现类
- 调用 configurePropertySources(environment, args) , 在此应用程序环境中添加、删除或重新排序任何PropertySources。
- MutablePropertySources sources = environment.getPropertySources();
?- 获取前面的 MutablePropertySources
- sources.addLast : 添加 defaultProperties
- 如果 args > 0 , 且可以添加 commonLine , 则添加CommandLineProperties
?- 其中会判断属性 commandLineArgs 是否会存在 ,存在则常用替换方式

// M1_24 伪代码
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService) conversionService);
}
configurePropertySources(environment, args);
configureProfiles(environment, args);
}



C2- ConfigurationPropertySources.
M2_01- attach(environment);
- sources = ((ConfigurableEnvironment) environment).getPropertySources() : 获取 MutablePropertySources
- attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME) : 获取 PropertySource
- 如果 attached 为null 或者 不等于 sources , 则将 sources 替换原先的 attached

// Binder : 从一个或多个容器绑定对象的容器对象
M1_25- bindToSpringApplication
C3- Binder
M3_01- bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context,boolean allowRecursiveBinding, boolean create)
- context.clearConfigurationProperty() : 清空原属性
- handler.onStart(name, target, context) : BindHandler 开始绑定
- bindObject : 将 属性绑定到对象
- handleBindResult : 返回 绑定结果


private <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context,boolean allowRecursiveBinding, boolean create) {
try {
Bindable<T> replacementTarget = handler.onStart(name, target, context);
if (replacementTarget == null) {
return handleBindResult(name, target, handler, context, null, create);
}
target = replacementTarget;
Object bound = bindObject(name, target, handler, context, allowRecursiveBinding);
return handleBindResult(name, target, handler, context, bound, create);
}catch (Exception ex) {
return handleBindError(name, target, handler, context, ex);
}
}

configureIgnoreBeanInfo 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码// 其中仅设置了2个属性 : 

// 属性一 : spring.beaninfo.ignore , 用于
environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE)

// 设置二 : 设置到 System 中
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString())

//那么该属性是为了干什么 ? -> spring.beaninfo.ignore
当值为 true 时 , 意味着跳过对 BeanInfo 类的搜索 .
如果经历了对不存在的 BeanInfo 类的重复 ClassLoader 访问,可以考虑将这个标志切换为“ true”,以防在启动或延迟加载时这种访问开销很大

但是现阶段所有 BeanInfo 元数据类,默认值是"false"

2.3 Banner 的打印

纯粹是好奇 , 过来看一眼

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
java复制代码
M1_28- printBanner : 准备 Banner 类


// 代码详情
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null)
? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());

SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
// 核心代码 -> 调用类 SpringBootBanner
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

// 核心类 SpringBootBanner
C- SpringBootBanner
M- printBanner
- printStream.println(line) : 逐行打印那个 Spring
- 打印版本号
?- :: Spring Boot :: (v2.3.1.RELEASE)

// ps : 点进去就知道了 , 逐行打印
  • 提供了一个开关
  • 构建一个 SpringApplicationBannerPrinter ,
  • 调用 print 生成了一个 Banner 对象

2.4 createApplicationContext 逻辑

该逻辑为创建 ApplicationContext 的相关逻辑 , 这里先简单过一下 :

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
java复制代码
C- SpringApplication
M1_30- createApplicationContext
- Class<?> contextClass = this.applicationContextClass;
IF- contextClass为null
- 根据 webApplicationType 类型,获得 ApplicationContext 类型
- AnnotationConfigServletWebServerApplicationContext 
- AnnotationConfigApplicationContext
- AnnotationConfigReactiveWebServerApplicationContext
- 根据 contextClass 创建 ApplicationContext 对象


// M1_30 伪代码
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 根据不同 webApplicationType 准备不同的 ContextClass
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
// 反射构造器方法获得 context 实现类
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}


// ApplicationContext 核心流程值得深入 , 后面开一个单章来详细是说

PS:M1_01_03 生成一个 ConfigurableApplicationContext
data-applicationContext.jpg

PS : ApplicationContext 体系结构

ApplicationContext.png

这里补充一下 Reactive 的区别

SpringBoot-Stack.jpg

如图所示 , Reactive 是 Spring 中一个重要的技术栈 , Reactive 可以用于构建响应性、弹性、弹性和消息驱动的企业级反应系统.

WebFlux 并不是 Spring MVC 替代,它主要应用还是在异步非阻塞编程模型上 , 使用了 WebFlux 的应用,其整体响应时间更短,启动的线程数更少,使用的内存资源更少。同时,延迟越大,WebFlux 的优势越明显

具体可以参考这篇文档 @ blog.csdn.net/u010862794/…

2.5 中间操作

M1_11 获取 SpringBootExceptionReporter 的处理类

1
2
3
4
5
6
7
java复制代码getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);


// Spring.factories
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

M1_12 callRunners : 干什么

该方法主要是运行 ApplicationRunner

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
java复制代码// callRunners 主流程
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}


@Component
public class SourceTestLogic implements ApplicationRunner {

private Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public void run(ApplicationArguments args) throws Exception {
logger.info("------> run <-------");
}
}

// 简单点说 , ApplicationRunner 初始化启动就是这里做的

2.6 Context 的三次处理

Context 的二次处理分为 三步 :

  • prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    • 设置 Context 的前置属性
  • refreshContext(context);
    • 注入 Bean , 注册监听器 , 初始化并发布事件
  • afterRefresh(context, applicationArguments);
    • 现阶段为空实现

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
java复制代码// prepareContext(context, environment, listeners, applicationArguments, printedBanner);
M1_35- prepareContext : 准备 ApplicationContext 对象,主要是初始化它的一些属性
-> 1 设置 context 的 environment 属性
-> 2 调用 #postProcessApplicationContext(ConfigurableApplicationContext context) 方法,
?- 设置 context 的一些属性 -> M1_36
-> 3 调用 #applyInitializers(ConfigurableApplicationContext context) 方法,
?- 初始化 ApplicationContextInitializer -> applyInitializers
-> 4 调用 SpringApplicationRunListeners#contextPrepared
?- 通知 SpringApplicationRunListener 的数组,Spring 容器准备完成
-> 5 设置 beanFactory 的属性
-> 6 调用 #load(ApplicationContext context, Object[] sources) 方法,加载 BeanDefinition 们
?-
-> 创建 BeanDefinitionRegistry 对象
-> 设置 loader 属性
-> 执行BeanDefine 加载

// M1_35 伪代码
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 为容器设置 environment
context.setEnvironment(environment);
// 设置容器 classloader 和 conversionService , 即容器中类的加载工具
postProcessApplicationContext(context);
// 在刷新上下文之前,将任何ApplicationContextInitializers应用于该上下文
applyInitializers(context);
// listeners 执行 , 在创建并准备好ApplicationContext之后调用,但在加载源之前调用。
listeners.contextPrepared(context);
if (this.logStartupInfo) {
// 打印启动日志配置
logStartupInfo(context.getParent() == null);
// 打印 active profile 信息
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// beanFactory 注入相关Bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}

if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
// 添加一个新的BeanFactoryPostProcessor
// 该新的BeanFactoryPostProcessor将在刷新之前应用于此应用程序上下文的内部Bean工厂,然后再评估任何Bean定义。
// 在上下文配置期间调用。
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// -> M1_38
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}

M1_36- postProcessApplicationContext : 在ApplicationContext中应用任何相关的后处理
- beanNameGenerator 存在则设置到 context.getBeanFactory().registerSingleton 中
- resourceLoader 存在且 为 GenericApplicationContext类型 , 则 setResourceLoader
- resourceLoader 存在且 为 resourceLoader 则 setClassLoader
- addConversionService 为 true 则设置到 BeanFactory 中

// M1_36 伪代码
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
if (this.addConversionService) {
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
}
}


M1_37- applyInitializers
FOR- (ApplicationContextInitializer initializer : getInitializers()) : for 循环处理 Initializers
- Assert判断 是否为 ApplicationContextInitializer 的实例
- initializer.initialize(context) 初始化对象


M1_38- load
- 这里主要是创建 BeanDefinitionLoader

protected void load(ApplicationContext context, Object[] sources) {
// 创建 BeanDefinitionLoader , 直接 new 的
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
// beanName 生成类
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
// -> M5_01
loader.load();
}

C5- BeanDefinitionLoader
M5_01- loader
?- 这里会循环调用 load source

// M5_01 伪代码
for (Object source : this.sources) {
count += load(source);
}

refresh 流程

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
61
62
63
64
65
66
67
68
java复制代码
C- AbstractApplicationContext
M1_50- refreshContext(context);
- refresh(context);
- 如果有 ShutdownHook (关闭钩子) , 则注册 registerShutdownHook


@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新。
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 告诉子类刷新内部bean工厂
prepareBeanFactory(beanFactory);

try {
// 允许在上下文子类中对bean工厂进行后处理
postProcessBeanFactory(beanFactory);

// 调用在上下文中注册为bean的工厂处理器
// IOC 的主要逻辑就在其中
invokeBeanFactoryPostProcessors(beanFactory);

// 注册拦截Bean创建的Bean处理器
registerBeanPostProcessors(beanFactory);

// 初始化此上下文的消息源
initMessageSource();

// 初始化此上下文的事件多主控器.
initApplicationEventMulticaster();

// 初始化特定上下文子类中的其他特殊bean.
onRefresh();

// 检查侦听器bean并注册它们.
registerListeners();

// 实例化所有剩余的(非lazy-init)单例.
finishBeanFactoryInitialization(beanFactory);

//最后一步:发布相应的事件
finishRefresh();
}catch (BeansException ex) {

// 销毁已创建的单件以避免资源悬空
destroyBeans();

// 重置“活动”标志.
cancelRefresh(ex);

// 将异常传播到调用方.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

// 这一部分也是 AbstractApplicationContext 的主要流程 , 放在后续 ApplicationContext 单章说

afterRefresh 流程

PS : 这是一个空实现

1
java复制代码M1_60- afterRefresh

2.7 Listener 处理

Application 启动时 , Listener 总共涉及到四个操作 :

  • getRunListeners
  • listener.starting
  • listener.started
  • listener.running

以我这微薄的英语水平 , 这里面怕是有个进行时和一个过去时 , 哈哈哈哈哈

可以看到 , 第一步和第四步目的都比较明确 , 主要来看看第二 . 三步

getRunListeners

1
2
3
4
5
6
7
8
java复制代码C- SpringApplication
M- getRunListeners
- getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)

// 可以看到 , 从 Factories 中获取的 , 先阶段只有一个 EventPublishingRunListener
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

listener.starting

1
2
3
4
5
6
7
8
9
java复制代码//这里的 starting 是 EventPublishingRunListener 运行
// 具体事件的处理逻辑 , 我们后续文档继续深入

C- EventPublishingRunListener
M- starting()
- this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));

C- AbstractApplicationEventMulticaster
?- 将所有事件多播给所有注册的侦听器,并在调用线程中调用它们 , 简单点说就是事件群发

listeners.started(context)

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码// 这里的事件就更多了

for (SpringApplicationRunListener listener : this.listeners) {
listener.started(context);
}

这里还是 EventPublishingRunListener

@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}

listener.running

1
2
3
java复制代码// 发布 ReadyEvent
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);

篇幅有限 , 就不详细看看哪些执行了

2.8 其他处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码


private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {
try {
try {
// 处理退出码
handleExitCode(context, exception);
if (listeners != null) {
listeners.failed(context, exception);
}
}finally {
reportFailure(exceptionReporters, exception);
if (context != null) {
context.close();
}
}
}catch (Exception ex) {
logger.warn("Unable to close ApplicationContext", ex);
}
ReflectionUtils.rethrowRuntimeException(exception);
}

三 . 总结

这一篇对 SpringBoot 的大概流程简单过了一遍 , 篇幅有限有几个点暂时先没纳入 , 后续补充

  • @SpringApplication 注解
  • SpringApplicationContext 的始末
  • Listener 的加载逻辑

更新记录

  • v20210804 : 更新布局 , 优化结构

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%