main方法启动时,springBoot启动流程的各个生命周期会以事件通知的方式,把事件告知其他程序
前期通过spring-spi获取所有监听事件的类
- spring启动的大体流程为以下的几个方法
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
75public class EventPublishingRunListener implements SpringApplicationRunListener {
...
private final SimpleApplicationEventMulticaster initialMulticaster = new SimpleApplicationEventMulticaster();
public EventPublishingRunListener(SpringApplication application, String[] args) {
// 通过springSPI获取所有的ApplicationListener,并添加到initialMulticaster字段中
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
// 1 开始
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
// 2 环境准备
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
/**
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
...
initializer.initialize(context);
}
}
*/
// contextPrepared之前 会调用SpringApplication 内置的 initialize,如上面的注释的代码
// 3 上下文准备
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
// 4 上下文已加载
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
// contextLoaded之后 会调用 [context.refresh](/posts/springbeanfactory流程解析),会实例化所有的bean(单例的、notLazy的)
// 在refresh阶段后,context的事件会通过context发出,context持有beanFactory, beanFactory在refresh期间会扫描所有的listener。
// 5 启动完成
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}
// 6 运行中
public void running(ConfigurableApplicationContext context) {
// 通过context发出事件,context持有beanFactory,beanFactory会扫描所有的ApplicationListener。
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
public void failed(ConfigurableApplicationContext context, Throwable exception) {
...
}
...
}
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
启动流程
1. starting(ApplicationStartingEvent)
正在进行时、代表容器刚开始运行了---发出程序开始事件
springDevTools就是用到了此事件,把类加载器给换了一下,起到了热部署的作用,后期咱们会有详细的分析
2. environmentPrepared(ApplicationEnvironmentPreparedEvent)
配置环境变量加载配置文件资源等---发出环境配置已就绪事件
nacos和springCloud远程加载配置文件就是用到了此事件,后期咱们会有详细的分析
事件发出之后,马上就要实例化ApplicationContext了,不同的WebApplicationType,context实例不同
不管什么样的context,都会持有beanFactory,并且都会向beanFactory注册一个非常重要的bean:ConfigurationClassPostProcessor
注册代码
AnnotationConfigUtils#registerAnnotationConfigProcessors
在beanFactory执行后置处理时,会调用此类
它的作用是:扫描beanFactory所有的bean,符合条件的生成beanDefinition并注册到beanFactory,然后继续扫描
如处理@PropertySources
、@ComponentScans
、@Component
、@Import
、@Configuration
等注解实例化完context后会发布事件通知,会调用ApplicationContextInitializer的initialize
3. contextPrepared(ApplicationContextInitializedEvent)
触发此事件之前会触发contextInitializer的initialize
容器准备---发出应用程序上下文初始化事件
contextPrepared之后会把main方法所在的启动类注册到beanFactory中,这样该类上的注解ComponentScan
等,就会被ConfigurationClassPostProcessor
处理
4. contextLoaded(ApplicationPreparedEvent)
容器已加载完毕---发出应用程序已准备就绪事件
contextLoaded之后 会调用 context.refresh,会实例化所有的bean(单例的、notLazy的)
refresh阶段比较复杂,基本上都是操作beanFactory完成bean的扫描、组装、初始化等逻辑
beanFactory可参考springBeanFactory流程解析
5. started(ApplicationStartedEvent)
发出应用程序已启动事件
6. running(ApplicationReadyEvent)
运行中---发出程序已做完事件
failed(ApplicationFailedEvent)
启动失败时的事件处理器,spring默认就是打印日志。
我们可以实现此事件的监听,项目启动失败之后直接报警等
总结
ApplicationContext这个是spring的容器(非常重要),启动的流程基本上都是围绕着他展开。
从各个事件的通知事件我们不难看出。从最开始的starting、environmentPrepared都是为applicationContext做准备。
根据不同的WebType实例化不同的applicationContext,之后context会持有environment,environment包含了所有的配置文件
然后再以context为中心进行initialize事件的触发、然后contextPrepared、contextLoaded、context.refresh
refresh工作比较复杂也是beanFactory的核心,具体可参考springBeanFactory流程解析
最后在做结尾的工作started和running