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
75
76
77public class EventPublishingRunListener implements SpringApplicationRunListener {
...
private final SimpleApplicationEventMulticaster initialMulticaster = new SimpleApplicationEventMulticaster();
public EventPublishingRunListener(SpringApplication application, String[] args) {
// 通过springSPI获取所有的ApplicationListener,并copy到initialMulticaster
// 如果ApplicationListener是以注解形式使用,非spi配置的。会在[refresh阶段](/posts/springbeanfactory流程解析)扫描所有以注解形式配置的listener
// 也就是说注解形式配置的listener,监听refresh之前的事件都是伪事件
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()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
*/
// prepared之前 会调用 mian方法启动的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的),包括以注解形式配置的listener
// 5 启动完成
public void started(ConfigurableApplicationContext context) {
// 在refresh阶段后,后续的事件会通过context发出,context持有beanFactory,beanFactory在refresh期间会扫描所有的listener。所以就不能仅仅调用spi配置的listener了
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
注册代码AnnotationConfigUtils#registerAnnotationConfigProcessors
=ConfigurationClassPostProcessor,在beanFactory执行后置处理时,会调用此类,并扫描所有的bean
实例化完后会发布事情通知容器已经实例化,调用ApplicationContextInitializer的initialize
3. contextPrepared -》ApplicationContextInitializedEvent
容器准备---发出应用程序上下文初始化事件
contextPrepared之后springBoot会把main方法所在的类注册到beanFactory中
beanFactory在执行beanFactory执行后置处理时,会调用ConfigurationClassPostProcessor
ConfigurationClassPostProcessor通过扫描beanFactory所有注册的bean上的注解继而扫描其他的bean(包)
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