1. 詳解Spring 中如何控制2個bean中的初始化順序
??開發過程中有這樣一個場景,2個 bean 初始化邏輯中有依賴關系,需要控制二者的初始化順序。實現方式可以有多種,本文結合目前對 Spring 的理解,嘗試列出幾種思路。
場景
假設A,B兩個 bean 都需要在初始化的時候從本地磁盤讀取文件,其中B加載的文件,依賴A中加載的全局配置文件中配置的路徑,所以需要A先于B初始化,此外A中的配置改變后也需要觸發B的重新加載邏輯,所以A,B需要注入彼此。
對于下面的模型,問題簡化為:我們需要initA()先于initB()得到執行。
1.1 方案一:立Flag
??可以在業務層自己控制A,B的初始化順序,在A中設置一個“是否初始化的”標記,B初始化前檢測A是否得以初始化,如果沒有則調用A的初始化方法,所謂的check-and-act。對于上述模型,實現如下:
[站外圖片上傳中...(image-a48682-1551843463104)]
執行效果:
A construct
B construct
A init
B init
??這種立flag的方法好處是可以做到lazy initialization
,但是如果類似邏輯很多的話代碼中到處充斥著類似代碼,不優雅,所以考慮是否框架本身就可以滿足我們的需要。
1.2 方案二:使用DependsOn
??Spring 中的 DependsOn 注解可以保證被依賴的bean先于當前bean被容器創建,但是如果不理解Spring中bean加載過程會對 DependsOn 有誤解;
1.3方案三:容器加載bean之前
??Spring 框架中很多地方都為我們提供了擴展點,很好的體現了開閉原則(OCP)。其中 BeanFactoryPostProcessor
可以允許我們在容器加載任何bean之前修改應用上下文中的BeanDefinition
(從XML配置文件或者配置類中解析得到的bean信息,用于后續實例化bean)。
??在本例中,就可以把A的初始化邏輯放在一個 BeanFactoryPostProcessor
中。
[站外圖片上傳中...(image-8c8fa4-1551843463104)]
執行效果:
A init
A construct
B construct
B init
??這種方式把A中的初始化邏輯放到了加載bean之前,很適合加載系統全局配置,但是這種方式中初始化邏輯不能依賴bean的狀態。
1.4 方案四:事件監聽器的有序性
??Spring 中的 Ordered
也是一個很重要的組件,很多邏輯中都會判斷對象是否實現了 Ordered
接口,如果實現了就會先進行排序操作。比如在事件發布的時候,對獲取到的 ApplicationListener
會先進行排序。
所以可以利用事件監聽器在處理事件時的有序性,在應用上下文 refresh
完成后,分別實現A,B中對應的初始化邏輯。
2. Spring裝配Bean的過程
?? Spring裝配Bean的過程
1. 實例化;
2. 設置屬性值;
3. 如果實現了BeanNameAware接口,調用setBeanName設置Bean的ID或者Name;
4. 如果實現BeanFactoryAware接口,調用setBeanFactory 設置BeanFactory;
5. 如果實現ApplicationContextAware,調用setApplicationContext設置ApplicationContext
6. 調用BeanPostProcessor的預先初始化方法;
7. 調用InitializingBean的afterPropertiesSet()方法;
8. 調用定制init-method方法;
9. 調用BeanPostProcessor的后初始化方法;
分析:
spring的兩個核心接口BeanFactory和ApplicationContext。BeanFactory主要定義容器的核心方法,ApplicationContext加以擴展,主要使用的還是ApplicationContext。在ApplicationContext的子類中,AbstractApplicationContext中的refresh()方法定義了容器加載配置文件及裝配Bean的過程。
AbstractApplicationContext#refresh()
代碼如下:
容器在啟動之前要獲得對象鎖,保證容器只有一個啟動synchronized
/容器在啟動之前要獲得對象鎖,保證容器只有一個啟動synchronized
//1 準備刷新工作,刷新前的預處理
prepareRefresh();
// 2 實例化BeanFactory,將配置文件的信息裝入到容器的Bean定義的注冊表(BeanDefinitionRegistry中),此時Bean還未初始化
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3 準備BeanFactory 主要是加載一些類,
prepareBeanFactory(beanFactory);
try {
// 4 留作子類實現
//抽象的方法,當前未做處理。子類通過重寫這個方法來在BeanFactory創建并預準備完成以后做進一步的設置
postProcessBeanFactory(beanFactory);
/*******以上是BeanFactory的創建及預準備工作*****/
// 5 調用工廠后處理器
invokeBeanFactoryPostProcessors(beanFactory);
//6 注冊bean后處理器,注冊BeanPostProcessor(Bean的后置處理器)
registerBeanPostProcessors(beanFactory);
//7 初始化消息源,初始化MessageSource組件(做國際化功能;消息綁定,消息解析);
initMessageSource();
//8 初始化事件廣播器
initApplicationEventMulticaster();
//9 鉤子方法
onRefresh();
// 10 注冊監聽器,給容器中將所有項目里面的ApplicationListener注冊進來
registerListeners();
//11 完成bean實例化(除lazy-init),并放入緩存中,
// 初始化所有剩下的單實例bean;
finishBeanFactoryInitialization(beanFactory);
// 12 廣播刷新事件,完成BeanFactory的初始化創建工作;IOC容器就創建完成;
finishRefresh();
}
refresh()函數的重點步驟:
2.1 prepareRefresh():刷新前的預處理;
??initPropertySources()
是初始化上下文環境,容器的一些信息這個時候加載了進來比如文件路徑信息;getEnvironment().validateRequiredProperties()
查看標示為必填的屬性信息是否都有了,校驗配置文件的屬性和合法性。
2.2 obtainFreshBeanFactory:實例化beanFactory
??查看
refreshBeanFactory
,beanFactory
創造過程。繼續追蹤到AbstractApplicationContext
的子類:AbstractRefreshableApplicationContext
??refreshBeanFactory:
- 先判斷是否已經存在
BeanFactory
,如果存在,則銷毀所有的bean,并關閉beanFactory
;防止重復加載beanFactory
; - 創建一個
beanFactory
(類型為DefalutListableBeanFactory
),最重要的BeanFactory
;spring注冊及加載bean就靠它。其實這里還是一個基本的容器 - 初始化
XmlBeanDefinitionReader
用來讀取xml,并加載解析 - 設置為全局變量,
AbstractRefreshableApplicationContext
持有DefaultListableBeanFactory
引用
customizeBeanFactory
,在類AbstractRefreshableApplicationContext
中,這里是根據AbstractRefreshableApplicationContext
類的屬性為Beanfactory
設置值。
allowBeanDefinitionOverriding屬性是指是否允對一個名字相同但definition不同進行重新注冊,默認是true。 allowCircularReferences屬性是指是否允許Bean之間循環引用,默認是true.
默認情況下兩個屬性都為空,既然是可擴展的,那么自然可以自己設置屬性,方法就是繼承ClassPathXmlApplicationContext
并復寫customizeBeanFactory
方法為兩個屬性設置值即可。
2.3 prepareBeanFactory:BeanFactory的預準備工作
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 1)、設置BeanFactory的類加載器
beanFactory.setBeanClassLoader(getClassLoader());
// 1)、設置支持表達式解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
?
// 2)、添加部分BeanPostProcessor【ApplicationContextAwareProcessor】
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 3)、設置忽略的自動裝配的接口EnvironmentAware、EmbeddedValueResolverAware、xxx;
// 這些接口的實現類不能通過類型來自動注入
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
?
// 4)、注冊可以解析的自動裝配;我們能直接在任何組件中自動注入:
//BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
/* 其他組件中可以通過下面方式直接注冊使用
@autowired
BeanFactory beanFactory */
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
?
// 5)、添加BeanPostProcessor【ApplicationListenerDetector】后置處理器,在bean初始化前后的一些工作;
// 將當前的ApplicationContext對象交給ApplicationContextAwareProcessor類來處理,從而在Aware接口實現類中的注入applicationContext
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
?
// 6)、添加編譯時的AspectJ;
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
?
// 7)、給BeanFactory中注冊一些能用的組件;
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
// 環境信息ConfigurableEnvironment
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
//系統屬性,systemProperties【Map<String, Object>】
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
//系統環境變量systemEnvironment【Map<String, Object>】
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
總結:
1.設置類加載器;
2.設置EL表達式解析器(Bean創建完成填充屬性時使用)和屬性注冊解析器
3.利用BeanPostProcessor的特性給各種Aware接口的實現類注入ApplicationContext中對應的屬性
4.設置各種Aware接口的實現類為忽略自動裝配
5.設置自動裝配的類(BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext)
6.如果BeanFactory中存在loadTimeWeaver的bean,那么需要添加動態織入功能
7.注冊各種可用組件(environment,systemProperties,systemEnvironment)
2.4 執行BeanFactoryPostProcessor的后置處理器方法(BeanFactory)
??Spring中BeanFactoryPostProcessor
和BeanPostProcessor
都是Spring初始化bean時對外暴露的擴展點。兩個接口從名字看起來很相似,但是作用及使用場景卻不同。
??Spring IoC容器允許BeanFactoryPostProcessor
在容器實例化任何bean之前讀取bean的定義(配置元數據),并可以修改它。同時可以定義多個BeanFactoryPostProcessor
,通過設置'order'屬性來確定各個BeanFactoryPostProcessor
執行順序。
?? 注冊一個BeanFactoryPostProcessor
實例需要定義一個Java類來實現BeanFactoryPostProcessor
接口,并重寫該接口的postProcessorBeanFactory
方法。通過beanFactory
可以獲取bean的定義信息,并可以修改bean的定義信息。這點是和BeanPostProcessor
最大區別!
如下,Spring中bean工廠后置處理器也就是BeanFactoryPostProcessor
接口:
??注釋可知允許我們在工廠里所有的bean被加載進來后但是還沒初始化前,對所有bean的屬性進行修改也可以add屬性值。
注意:
BeanFactoryPostProcessor
可以與bean definitions
打交道,但是千萬不要進行bean實例化(感覺這里應該說的是不要在BeanFactoryPostProcessor
進行可能觸發bean實例化的操作)。這么做可能會導致bean被提前實例化,會破壞容器造成預估不到的副作用。如果你需要hack到bean實例化過程,請考慮使用BeanPostProcessor
。
??definitions
進行一定hack,但是也僅此而已了。絕對不允許在BeanFactoryPostProcessor中觸發到bean的實例化!!!
doc說得很清楚but never bean instances. Doing so may cause premature bean instantiation, violating the container and causing unintended side-effects. 下面就列舉錯誤使用造成的兩種典型“副作用”。
錯誤1)使用注解進行依賴注入失敗
@Component
public class PrematureBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<String, BBean> map = beanFactory.getBeansOfType(BBean.class);
for (BBean bBean : map.values()) {
assert bBean.getABean() == null;
}
}
}
@Component("bBean")
public class BBean {
@Autowired
private ABean aBean;
public ABean getABean() {
return aBean;
}
}
@Component
public class ABean {
private String name = "a";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
??從裝配bean的AbstractApplicationContext#refresh()
方法中可以看到的是postProcessBeanFactory(beanFactory)
; 首先invoke了容器中的BeanFactoryPostProcessor
實現類,其中當然就包括PrematureBeanFactoryPostProcessor
,此時通過beanFactory.getBeansOfType
觸發了bean提前實例化。
??按理說,bean提前實例化也應該沒問題的,aBean
也應該是能夠被注入的呀!那為啥最終不是這個結果呢。讓我們研究下@Resource @AutoWired
這種注解是如何注入依賴的,如何起作用的就明白了。
@AutoWired起作用依賴AutowiredAnnotationBeanPostProcessor, @Resource依賴CommonAnnotationBeanPostProcessor;
這倆都是BeanPostProcessor
的實現。那BeanPostProcessors
在何處被spring invoke呢,參見registerBeanPostProcessors(beanFactory);
在postProcessBeanFactory(beanFactory);
后面被調用,也就是說BBean
被觸發提前初始化的時候,AutowiredAnnotationBeanPostProcessor
還沒有被注冊自然也不會被執行到,自然ABean=null
。
Spring的BeanPostProcessor和BeanFactoryPostProcessor區別
BeanPostProcessor:bean
級別的處理,針對某個具體的bean進行處理,bean實例化之后執行;能在spring容器實例化bean之后,在執行bean的初始化方法前后,添加一些自己的處理邏輯
BeanFactoryPostProcessor
:是針對bean容器的,它的實現類可以在當前BeanFactory
初始化(spring容器加載bean定義文件)后,bean實例化之前修改bean的定義屬性,達到影響之后實例化bean的效果。BeanFactory
級別的處理,是針對整個Bean的工廠進行處理,bean實例化之前執行;Spring允許BeanFactoryPostProcessor
在容器實例化任何其它bean之前讀取配置元數據,并可以根據需要進行修改,例如可以把bean的scope從singleton改為prototype,也可以把property的值給修改掉。可以同時配置多個BeanFactoryPostProcessor
,并通過設置’order
’屬性來控制各個BeanFactoryPostProcessor
的執行次序。
2.5 registerBeanPostProcessors:注冊BeanPostProcessor(Bean的后置處理器)
registerBeanPostProcessors
從名稱可以看出是用來注冊BeanPostProcessor
的。下面是BeanPostProcessor
的代碼,可以看出只有兩個方法。
postProcessBeforeInitialization
作用:在bean實例化、依賴注入之后,初始化(顯示)之前執行。什么叫顯示初始化?我們知道在bean實例化之前,已經初始化對象了,這里顯示指的是,要給bean的某些屬性手動賦值,或手動去執行的某些方法。比如:init-method方法,其就是在實例化之后調用的。
postProcessAfterInitialization
作用:在bean實例化、依賴注入之后,初始化(顯示)之后執行。
上面講到的BeanFactoryPostProcessor
是用來處理bean工廠或者是bean定義的,BeanPostProcessor
是用來處理bean實例的
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
//1)、獲取所有的 BeanPostProcessor;后置處理器都默認可以通過PriorityOrdered、Ordered接口來執行優先級
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
?
//檢查器,檢查所有的BeanPostProcessor
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
?
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
?
/* 2)、先注冊PriorityOrdered優先級接口的BeanPostProcessor;
把每一個BeanPostProcessor;添加到BeanFactory中
beanFactory.addBeanPostProcessor(postProcessor);*/
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
?
// 3)、再注冊Ordered接口的
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
?
// 4)、最后注冊沒有實現任何優先級接口的
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
?
// 5)、最終注冊MergedBeanDefinitionPostProcessor;
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
?
// 6)、注冊一個ApplicationListenerDetector;判斷創建完成的bean是否監聽器
/* 在Bean創建完成后ApplicationListenerDetector.postProcessAfterInitialization()中檢查是否是ApplicationListener 類型,如果是applicationContext.addApplicationListener((ApplicationListener<?>) bean);如果是添加到容器中 */
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
2.6 initMessageSource();國際化
初始化MessageSource
組件(做國際化功能;消息綁定,消息解析);
protected void initMessageSource() {
// 1)、獲取BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
/*
2)、看容器中是否有id為messageSource的,類型是MessageSource的組件
如果有賦值給messageSource,如果沒有自己創建一個DelegatingMessageSource;
MessageSource作用:取出國際化配置文件中的某個key的值;能按照區域信息獲取;
*/
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) {
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.isDebugEnabled()) {
logger.debug("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// 如果沒有自己創建一個DelegatingMessageSource;
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
//把創建好的messageSource注冊到容器中,以后獲取國際化配置文件的值的時候,可以自動注入MessageSource;
//注入后通過這個方法使用MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale);
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
"': using default [" + this.messageSource + "]");
}
}
}
2.7 初始化事件派發器initApplicationEventMulticaster()
protected void initApplicationEventMulticaster() {
//1)、獲取BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判斷容器中是否有applicationEventMulticaster 的這個bean ,如果有獲取,沒有創建
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
//2)、從BeanFactory中獲取applicationEventMulticaster的ApplicationEventMulticaster;
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
//3) 個SimpleApplicationEventMulticaster 類型的 applicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
//4)、將創建的ApplicationEventMulticaster添加到BeanFactory中,以后其他組件直接自動注入
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
2.8 onRefresh();留給子容器(子類)
類重寫AbstractApplicationContext.onRefresh()
這個方法,在容器刷新的時候可以自定義邏輯;
2.9 registerListeners();檢查和注冊 Listener
將所有項目里面的ApplicationListener
注冊到容器中;
protected void registerListeners() {
//1、從容器中拿到所有的ApplicationListener
for (ApplicationListener<?> listener : getApplicationListeners()) {
//2、將每個監聽器添加到事件派發器中;
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 1.獲取所有的ApplicationListener
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
//2、將每個監聽器添加到事件派發器中;
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
?
// earlyApplicationEvents 中保存之前的事件,
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
//3、派發之前步驟產生的事件;
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
2.10 finishBeanFactoryInitialization(beanFactory);初始化所有剩下的單實例bean
在完成BeanFactory
初始化之時,會初始化容器內所有單例非懶加載對象,供后續業務邏輯進行依賴注入等使用,具體實現在finishBeanFactoryInitialization(beanFactory)
內部的最后一行代碼:
// 預實例化所有非懶加載單例Bean
beanFactory.preInstantiateSingletons();
具體的preInstantiateSingletons
實現如下:
如上所示代碼:
beanNames = new ArrayList<String>(this.beanDefinitionNames);
- 獲取容器內加載的所有BeanDefinition
for (String beanName : beanNames)
- 遍歷初始化所有非懶加載單例Bean
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
- Bean定義公共的抽象類是
AbstractBeanDefinition
,普通的Bean在Spring加載Bean定義的時候,實例化出來的是GenericBeanDefinition
- 而Spring上下文包括實例化所有Bean用的
AbstractBeanDefinition
是RootBeanDefinition
- 這時候就使用
getMergedLocalBeanDefinition
方法做了一次轉化,將非RootBeanDefinition
轉換為RootBeanDefinition
以供后續操作。 - 注意如果當前
BeanDefinition
存在父BeanDefinition
,會基于父BeanDefinition
生成一個RootBeanDefinition
,然后再將調用OverrideFrom子BeanDefinition
的相關屬性覆寫進去。
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit())
- 如果Bean不是抽象的,是單例的,不是懶加載的,則開始創建單例對象通過調用getBean(beanName)方法初始化
具體getBean函數實現如下所示:
[站外圖片上傳中...(image-a39a5e-1551843463104)]
進一步調用了如下方法,其中有參數:
final String beanName = transformedBeanName(name);
- 如果是
FactoryBean
,會去掉Bean開頭的&符號; - 可能存在傳入別名且別名存在多重映射的情況,這里會返回最終的名字,如存在多層別名映射
A->B->C->D
,傳入D,最終會返回A
Object sharedInstance = getSingleton(beanName);
- 根據beanName從緩存中獲取Bean ;從緩存中獲取
BeanInstance
,根據不同的情況這個Bean實例做處理,或直接返回, - 這里先嘗試從緩存中獲取,獲取不到再走后面創建的流程
- 獲取到有兩種情況,一種是Bean創建完成存儲到最終的緩存中。
- 另一種是未創建完成,但先預存到一個單獨的緩存中,這種是針對可能存在循環引用的情況的處理。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
- 這里主要處理實現了
FactoryBean
的情況,需要調用重寫的getObject
()方法來獲取實際的Bean實例。真正的bean 返回處理
if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
- 原型對象不允許循環創建,如果是原型對象則拋異常
- 假設循環依賴的時候,如果我們已經開始在當前線程中創建此bean實例,但是還沒有創建完成,則失敗;
- 例如此時是A依賴于B,但是B不依賴于A,B也沒有任何屬性依賴于A,則不存在循環依賴,那么無論B初始化,未初始化都不會有以下情況。但是如果B依賴于A,A在獲取依賴的Bean是激活創建B的方法,那么B創建過程中就會出現以下情況。就會出現循環依賴錯誤。如果A,B 是單例的并且A的構造函數不包含B,B的構造函數不包含A,spring還是可以通過提前暴露實例地址處理這種依賴,但是其它情況spring也無能為力了。
BeanFactory parentBeanFactory = getParentBeanFactory();
- 獲取父bean工廠
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
return parentBeanFactory.getBean()
- 如果存在父bean工廠并且沒有配置該bean,則從父bean工廠創建
markBeanAsCreated(beanName);
- 進行已創建標記
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
- 根據名字獲取合并過的對應的RootBeanDefinition
- 獲取緩存的BeanDefinition對象并合并其父類和本身的屬性。
- 上面初始化得到的Bean的BeanDefinition用上
- 轉換BeanDefinition
String[] dependsOn = mbd.getDependsOn();
- 獲取依賴的Bean
- 確保當前Bean依賴的相關Bean先完成初始化工作
- depends-on標簽;depend-on用來表示一個Bean的實例化依靠另一個Bean先實例化
if (mbd.isSingleton()) {
- 開始創建Bean實例了,如果是單例的,那么會創建一個單例的匿名工廠
else if (mbd.isPrototype()) {
- 原型模式 ,則不需要創建單例的工廠
1.singleton模式通過getSingleton方法,這個里面創建對象時會先校驗緩存是 否已經存在該對象;
2.prototype模式直接創建對象,
3.其他類型的則可以通過自定義Scope來實現邏輯控制,
設想一下如果把對象放到第三方緩存中則可在這邊自定義一個Scope。
最終bean的構造委托給了createBean