大家好,又見面了,我是你們的朋友全棧君。
前言
我們知道,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及其他配置的初始化。
相關文章:
- 深入了解Spring容器初始化(一):上下文的初始化;
- 深入了解Spring容器初始化(二):BeanFactory的初始化;
- 深入了解Spring容器初始化(三):事件及其他配置的初始化;
一、初始化資料源
調用
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
,“階段”視為 0,會被最先處理;Bean
4、釋出上下文重新整理完畢事件
這個操作其實也很簡單,其實就是調用時間廣播器推送一個
ContextRefreshedEvent
事件:
public class ContextRefreshedEvent extends ApplicationContextEvent {
public ContextRefreshedEvent(ApplicationContext source) {
super(source);
}
}
複制
這個事件裡唯一一個參數就是上下文本身。
這一部分主要邏輯在事件推送上,後續會在專門的文章分析 spring 提供的事件機制,這裡就不過多展開。
總結
本文内容比較零散,主要幹三件事:
- 初始化消息源相關元件:
-
:初始化上下文使用的消息源;initMessageSource
-
:上下文重新整理時的回調函數,但是一般隻用于加載onRefresh
;ThemeSource
-
- 初始化事件相關元件:
-
:初始化事件廣播器;initApplicationEventMulticaster
-
:注冊容器中的事件監聽器registerListeners
;ApplicationListener
-
- 初始化
中所有非抽象的非懶加載BeanFactory
;Bean
- 完成重新整理:
- 清空上下文中的資源緩存;
- 初始化并調用
生命周期處理器;Bean
- 釋出上下文重新整理時間;
- 注冊并初始化用于支援 JMX 的元件;
釋出者:全棧程式員棧長,轉載請注明出處:https://javaforall.cn/170760.html原文連結:https://javaforall.cn