深入理解Spring容器初始化(三):事件及其他配置的初始化
概述
我们知道,spring 的启动其实就是容器的启动,而一般情况下,容器指的其实就是上下文 ApplicationContext
。
AbstractApplicationContext
作为整个 ApplicationContext
体系中最高级的抽象类,为除了 ComplexWebApplicationContext
和 SimpleWebApplicationContext
这两个容器外的全部容器,规定好了 refresh
的整体流程,所有的容器在完成一些自己的初始化配置后,都需要调用该 refresh
方法,依次完成指定内容的初始化。
也就是说,读懂了 AbstractApplicationContext.refresh()
方法,其实就读懂了容器的启动流程:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// ================= 一、上下文的初始化 =================
// 准备上下文
prepareRefresh();
// 通知子类刷新内部工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备bean工厂以便在当前上下文中使用
prepareBeanFactory(beanFactory);
try {
// ================= 二、BeanFactory的初始化 =================
// 对工厂进行默认后置处理
postProcessBeanFactory(beanFactory);
// 使用后置处理器对工厂进行处理
invokeBeanFactoryPostProcessors(beanFactory);
// 注册Bean后置处理器
registerBeanPostProcessors(beanFactory);
// ================= 三、事件,Bean及其他配置的初始化 =================
// 初始化此上下文的消息源
initMessageSource();
// 为此上下文初始化事件广播者
initApplicationEventMulticaster();
// 初始化特定上下文子类中的其他特殊bean
onRefresh();
// 检查侦听器bean并注册
registerListeners();
// 实例化所有非懒加载的剩余单例
finishBeanFactoryInitialization(beanFactory);
// 完成刷新
finishRefresh();
}
// ================= 异常处理 =================
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例
destroyBeans();
// 重置上下文的激活状态
cancelRefresh(ex);
throw ex;
}
finally {
// 重置内部的一些元数据缓存
resetCommonCaches();
}
}
}
从总体来看,该方法描述的初始化过程大概分为三步:
- 上下文的初始化;
BeanFactory
初始化;- 事件,Bean及其他配置的初始化;
笔者将基于 spring 源码 5.2.x
分支,分别通过三篇文章从源码分析 spring 容器的初始化过程。
本文是其中的第三篇文章,将介绍上下文中事件,Bean及其他配置的初始化。
相关文章:
一、初始化数据源
调用 AbstarctApplicationContext.initMessageSource()
用于初始化上下文所使用的数据源对象 MessageSource
,这个配置用于支持国际化的信息处理,一般情况下比较少会直接去配置它:
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果当前上下文否存在名为“messageSource”的Bean
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
// 若父容器没有MessageSource,就把它设置为父容器的MessageSource
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// 不存在就尝试获取父容器的MessageSource
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}
二、初始化事件广播者
调用 AbstarctApplicationContext.initApplicationEventMulticaster()
是初始化 spring 事件机制的第一步,它的作用很简单:
如果当前 BeanFactory
有名为 “applicationEventMulticaster”
的 ApplicationEventMulticaster
,就把它设置为当前上下文的事件广播器,否则就创建并在 BeanFactory
中注册一个SimpleApplicationEventMulticaster
实例作为当前上下文的事件广播器。
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 是否存在“applicationEventMulticaster”这个Bean
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// 如果存在就把它设置为当前上下文的事件广播器
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 没有就创建一个SimpleApplicationEventMulticaster作为当前上下文的事件广播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
三、初始化特殊Bean
AbstarctApplicationContext.onRefresh()
用于在完成上下文与 BeanFactory
初始化后去初始化一些特殊的 Bean
,其实从方法名就可以看出来,这个方法主要是作为上下文初步刷新完毕后的回调使用。
在 AbstarctApplicationContext
中只提供了空实现,实际上也只有很少的实现类会去重新实现这个方法,至少在 5.2.x
里面,关于这个方法的有用实现只有:
UiApplicationContextUtils.initThemeSource(this)
该代码用于初始化一些 spring 的“主题资源”,一般用于配合消息国际化进行一些处理。
四、注册事件监听器
当消息和事件相关的内容都准备就绪后,上下文会调用 AbstarctApplicationContext.registerListeners
方法以注册事件监听器 ApplicationListener
。
这一步代码不多,实际上逻辑也很简单:
- 向事件广播器注册已经被注册的上下文中的监听器;
- 向事件广播器注册还没有被实例化的监听器的
BeanName
; - 发布一些早期事件;
protected void registerListeners() {
// 向事件广播器注册已经被注册的上下文中的监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 向事件广播器注册指定的监听器,不过这里只注册BeanName,
// 因为有些监听器Bean是由FactoryBean生产的,而在这里FactoryBean实际上还没被生成出来
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 发布一些早期事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
这里有两个比较有意思的地方:
getApplicationListeners
获取的监听器实际上也是通过一个名为EventListenerMethodProcessor
的BeanFactoryPostProcessor
注册到上下文的;- 注册
BeanName
而不是直接注册Bean
这一点是为了迁就FactoryBean
。实际上在初始化BeanFactory
的时候,调用BeanFactoryPostProcessor
和注册BeanPostProcessor
也都专门对此进行了处理;
五、实例化工厂中的Bean
当调用 AbstarctApplicationContext.finishBeanFactoryInitialization
的时候,spring 会根据 BeanFactory
中已经注册的 BeanDefinition
实例化所有非懒加载的单例 Bean
:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 为BeanFactory设置ConversionService
// 该接口为spring转换器体系的入口
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 注册一个StringValueResolver,没有就从上下文的环境对象中获取
// 该解析器用于解析配置文件中的一些占位符以及SpEL表达式
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 若存在AOP使用的支持类加载时织入切面逻辑的类加载器,则优先将该Bean初始化
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 由于类加载器已经初始化完成,所以可以停用临时的类加载器了
beanFactory.setTempClassLoader(null);
// 锁定当前工厂的配置
beanFactory.freezeConfiguration();
// 初始化剩余未初始化的非懒加载单例Bean
beanFactory.preInstantiateSingletons();
}
这个方法总共干了五件事:
- 为
BeanFactory
设置类型转换服务ConversionService
; - 为
BeanFactory
设置占位符转换器StringValueResolver
; - 禁用临时的类加载器,若有则启用支持类加载时织入切面逻辑的类加载器;
- 锁定当前
BeanFactory
的配置; - 初始化剩余未初始化的非懒加载单例
Bean
;
这里我们重点关注 BeanFactory.preInstantiateSingletons()
方法,此处是实际上完成 Bean
初始化的代码:
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 遍历beanName,若BeanName是可以实例化的非懒加载单例Bean,则将其实例化
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 如果是FactoryBean
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
// 类型为SmartFactoryBean,则是否立刻实例化由SmartFactoryBean.isEagerInit()决定
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
// 类型不为SmartFactoryBean,则不立刻实例化
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 实例化bean
getBean(beanName);
}
}
}
// 获取所有实现了SmartInitializingSingleton接口的Bean,调用Bean初始化后回调afterSingletonsInstantiated
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
这一步主要干了两件事:
- 如果是允许实例化的非懒加载普通
Bean
,就直接初始化; - 如果是允许实例化的非懒加载
FactoryBean
,则判断它是否是SmartFactoryBean
:- 如果不是,则放弃直接初始化;
- 如果是,则根据
SmartFactoryBean.isEagerInit()
判断是否要直接初始化;
- 初始化所有可初始化的
Bean
后,如果这些Bean
实现了SmartInitializingSingleton
接口,则调用该接口提供的回调函数;
这里需要注意两点:
BeanFactory.getBean()
实际才是最终完成BeanFactory
创建Bean
实例操作的方法,在这个方法中将根据BeanDefinition
完成各自依赖的自动装配、Bean
的后置处理等操作,三级缓存也是在这个时候使用的,这部分的内容将会在后续另起一篇文章分析;- 此处仅预加载了
FactoryBean
,而没有懒加载FactoryBean
里面的Bean
,因此FactoryBean
提供的Bean
总是懒加载的; SmartInitializingSingleton
接口用于提供BeanFactory
在初始化全部非懒加载Bean
时调用的回调函数;
至此,BeanFactory
中所有可以预先初始化的 Bean
都完成的初始化,我们已经可以通过 BeanFactory
正常的去获取 Bean
了。
六、完成刷新
AbstractApplicationContext.finishRefresh()
是完成容器刷新的最后一步,它跟 AbstractApplicationContext.onRefresh()
一样是一个钩子方法。
protected void finishRefresh() {
// 清空资源缓存
clearResourceCaches();
// 初始化上下文的生命周期处理器
initLifecycleProcessor();
// 调用上下文的生命周期处理器
getLifecycleProcessor().onRefresh();
// 发布上下文刷新完毕事件
publishEvent(new ContextRefreshedEvent(this));
// 注册用于支持通过JMX管理spring的组件,这里不过多分析,
// 关于JMX具体可以参考这篇文章:https://www.wdbyte.com/java/jmx.html#_3-2-%E8%B5%84%E6%BA%90%E4%BB%A3%E7%90%86-mbean-server
LiveBeansView.registerApplicationContext(this);
}
1、清空上下文资源缓存
public void clearResourceCaches() {
this.resourceCaches.clear();
}
2、初始化上下文的生命周期处理器
protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 若存在名为“lifecycleProcessor”的bean,则设置为生命周期处理器
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this.lifecycleProcessor =
beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
if (logger.isTraceEnabled()) {
logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
}
}
// 若不存在名为“lifecycleProcessor”的bean,则创建一个DefaultLifecycleProcessor并设置为生命周期处理器
else {
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
if (logger.isTraceEnabled()) {
logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
}
}
}
3、生命周期处理
这里需要着重研究一下生命周期处理器的调用。
在 getLifecycleProcessor().onRefresh()
这一步,将会获取上一步设置到上下文中的 LifecycleProcessor
然后调用:
// AbstraceApplicationContext.getLifecycleProcessor()
LifecycleProcessor getLifecycleProcessor() throws IllegalStateException {
if (this.lifecycleProcessor == null) {
throw new IllegalStateException("LifecycleProcessor not initialized - " +
"call 'refresh' before invoking lifecycle methods via the context: " + this);
}
return this.lifecycleProcessor;
}
这里我们以默认的生命周期处理器 DefaultLifecycleProcessor
为例:
@Override
public void onRefresh() {
startBeans(true);
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
// 获取所有实现了Lifecycle接口的Bean,并按阶段分组装到不同的LifecycleGroup里
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
// 同时满足下述条件的Bean不会被处理
// 1.入参的autoStartupOnly为true
// 2.bean实现了SmartLifecycle接口
// 3.SmartLifecycle.isAutoStartup()方法返回false
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
// 若实现了SmartLifecycle接口,则返回SmartLifecycle.getPhase(),否则默认返回0
int phase = getPhase(bean);
LifecycleGroup group = phases.get(phase);
if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
group.add(beanName, bean);
}
});
// 按阶段从小到大排序,依次处理
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
Collections.sort(keys);
for (Integer key : keys) {
phases.get(key).start();
}
}
}
可以看到,这里针对 SmartLifecycle
接口的实现类做了很多特殊化的处理,默认情况下:
- 实现了
SmartLifecycle
接口的Bean
,需要保证SmartLifecycle.isAutoStartup
返回true
才会被处理; - 没实现
SmartLifecycle
接口,但是实现了Lifecycle
接口的Bean
会被直接处理;
并且,在处理 Bean
的时候,还会根据声明周期“阶段”按顺序从小到大排序:
- 实现了
SmartLifecycle
接口的Bean
,按照SmartLifecycle.getPhase
返回值排序从小到大执行; - 没实现
SmartLifecycle
接口,但是实现了Lifecycle
接口的Bean
,“阶段”视为 0,会被最先处理;
4、发布上下文刷新完毕事件
这个操作其实也很简单,其实就是调用时间广播器推送一个 ContextRefreshedEvent
事件:
public class ContextRefreshedEvent extends ApplicationContextEvent {
public ContextRefreshedEvent(ApplicationContext source) {
super(source);
}
}
这个事件里唯一一个参数就是上下文本身。
这一部分主要逻辑在事件推送上,后续会在专门的文章分析 spring 提供的事件机制,这里就不过多展开。
总结
本文内容比较零散,主要干三件事:
- 初始化消息源相关组件:
initMessageSource
:初始化上下文使用的消息源;onRefresh
:上下文刷新时的回调函数,但是一般只用于加载ThemeSource
;
- 初始化事件相关组件:
initApplicationEventMulticaster
:初始化事件广播器;registerListeners
:注册容器中的事件监听器ApplicationListener
;
- 初始化
BeanFactory
中所有非抽象的非懒加载Bean
; - 完成刷新:
- 清空上下文中的资源缓存;
- 初始化并调用
Bean
生命周期处理器; - 发布上下文刷新时间;
- 注册并初始化用于支持 JMX 的组件;