导读
承接上文聊聊SpringBoot应用生命周期(一),本片重点介绍准备工作完成之后,从容器刷新开始到SpringApplication.run()方法结束的流程。run()方法结束后,整个应用的启动流程就结束了。
启动阶段
启动阶段大面上分为两部分:
- 容器刷新
- Runners回调
容器刷新部分是本文重点。
一、容器刷新
这部分对应的就是spring framework原有的容器刷新流程。
1. 准备刷新容器
这个阶段做了一些容器刷新前的准备工作,如初始化环境变量,校验必要的变量是否提供。
2. 准备BeanFactory
这个阶段也有一些值得关注的行为。有一些BeanPostProcesser会在这个阶段添加。
- ApplicationContextAwareProcessor bean初始化之前,如果实现了某个Aware接口,对应的set方法会被调用。观察下面的代码,这一票Aware实际上注入的都是applicationContext
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
- ApplicationListenerDetector bean初始化完成后,如果实现了ApplicationListener,会被添加到ApplicationContext的监听器中
3. postProcessBeanFactory()
引用官方文档的说明
Modify the application context's internal bean factory after its standard
initialization. All bean definitions will have been loaded, but no beans
will have been instantiated yet. This allows for registering special
BeanPostProcessors etc in certain ApplicationContext implementations.
这个阶段允许再对容器内部的beanFactory进行一些修改。本阶段完成后,所有的bean definitions都被加载完毕,但都没有实例化。这里不免让人疑惑,这个方法的描述和签名都来自于BeanFactoryPostProcessor,为什么要在容器中单独出现?按照注释的描述:
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
似乎是为了方便子类容器直接实现此方法从而避免使用BeanFactoryPostProcessor。从结果来着,这个设计并没有达到预期效果,反而带来了额外的复杂度。本例中添加了WebApplicationContextServletContextAwareProcessor,用于bean初始化前设置ServletContextAware,ServletConfigAware实例bean的属性。
4. 回调所有BeanFactoryPostProcessor
对于注解驱动的springboot应用,在容器创建时就添加了ConfigurationClassPostProcessor
这个processor有多优秀呢,这里细数一下它主要做了下面几件事:
- 处理@ComponentScan注解。调用ComponentScanAnnotationParser,该parser又委托ClassPathBeanDefinitionScanner完成组件扫描的工作
- 递归处理@Import注解,无论是Import Configuration还是ImportSelector或ImportBeanDefinitionRegistrar
- 处理@ImportResource注解
这部分完成后,才符合官方文档的描述:所有的bean definitions都被加载,但没有实例化。
5. 注册BeanPostProcessor
注册BeanPostProcessor,需要注意的是对于注解驱动的springboot应用,在容器创建时就添加了一票BeanPostProcessor,这里列举开发者比较关心的:
- AutowiredAnnotationBeanPostProcessor
处理@Autowired注解 - CommonAnnotationBeanPostProcessor
处理@Resource注解
6. initApplicationEventMulticaster()
这部分注册了Spring事件发布器SimpleApplicationEventMulticaster到容器中,spring framework时代和springboot时代均只有这一个实现。
7. registerListeners()
引用官方文档说明
Add beans that implement ApplicationListener as listeners.
值得注意的是,@EventListener注解此时还未被处理,此注解标注的方法此时还不是监听器。也就是说此时仅有Springboot风格的监听器和spring framework风格实现了ApplicationListener的Bean作为监听器。
8. finishBeanFactoryInitialization()
冻结bean definition metadata,并实例化所有非延迟初始化的bean。这部分收尾阶段会调用SmartInitializingSingleton接口的afterSingletonsInstantiated()方法。EventListenerMethodProcessor(容器创建时就被添加)会处理@EventListener注解,生成对应的监听器并添加到容器中。
9. finishRefresh()
由DefaultLifecycleProcessor处理实现了Lifecycle接口相关的bean。这里通常是调用其start()方法。这一点在spring內建实现很少,但是对开发者比较有用。比如内嵌Netty服务时,可以考虑使用此接口,让spring管理生命周期。最后发布ContextRefreshedEvent。至此spring容器启动完成。
10. 注册ShutdownHook()
这个方法会在虚拟机shutdown时被回调,用于关闭容器。
二、Runners回调
1. 发布ApplicationStartedEvent
接上文,容器已经启动完毕,发布响应的事件。
2. runners回调
回调所有ApplicationRunner,CommandLineRunner。
3. 发布ApplicationReadyEvent
该事件发布完成后,表明SpringApplication已经可以服务请求。
至此,SpringApplication启动阶段分析完毕。下一篇分析结束阶段。
网友评论