【十八】Spring IOC 總結之getBean主流程和各個擴展點總結

一、getBean的流程簡介

Spring IOC主要分爲兩個大的部分,一部分是IOC容器的啓動,另一部分是getBean

getBean的部分我盜個圖

圖一來自https://juejin.im/post/5dec9fe76fb9a01608236cd3

1.簡單的講spring bean的生命週期

1.實例化 Instantiation  (上圖中的createBeanInstance:利用構造方法等途徑new出實例)

2.屬性賦值 Populate (上圖中的populateBean:往實例中注入各個屬性)

3.初始化 Initialization (上圖中的initializeBean:對實例進行一些後續初始化工作)

4.銷燬 Destruction

而在這1.2.3.件事的前後都有很多postProcessor和Aware可對bean做擴展 

2.對上圖getBean的順序總結:

1.最外層createBean方法中

利用BeanPostProcessor中的InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation

(如果有代理對象返回則直接調用每個BeanPostProcessor.postProcessAfterInitialization返回了,不需要調用後面的doCreateBean實例化了)

AbstractAutoProxyCreator就是一個InstantiationAwareBeanPostProcessor,它在這裏會被調用

2.實例化階段createBeanInstance

從該階段開始到結束,這些邏輯都在doCreateBean方法中

通過determineCandidateConstructors確定構造方法

如果沒有則使用無參構造方法

如果有工廠方法,則使用構造方法或工廠方法創建bean 

instantiateUsingFactoryMethod(beanName, mbd, args);

3.利用BeanPostProcessor中的MergedBeanDefinitionPostProcess回調postProcessMergedBeanDefinition合併bean定義

applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

4.加入三級緩存singletonFactories,如果該三級緩存被使用,它會調用所有BPP的getEarlyBeanReference返回早期暴露,例如AbstractAutoProxyCreator進行代理

5.populateBean填充階段

1.InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(允許用戶在Bean注入屬性前改變BeanDefinition的信息)

2.autowireByName或者autowireByType (用於在配置文件中通過<property>配置的屬性並且顯示在配置文件中配置了autowireMode屬性)

3.InstantiationAwareBeanPostProcessor.postProcessPropertyValues   ( @Autowire @Resource @Value @Inject 等註解的依賴注入過程,實際執行依賴注入邏輯的是AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues)

4.applyPropertyValues  (注入配置文件中<property>配置的屬性,早就不用XML配置文件來配置Bean的屬性了)

注:InstantiationAwareBeanPostProcessor接口至此三個方法都執行了

6.initializeBean初始化階段

1.執行Aware 方法 invokeAwareMethods(beanName, bean);

這裏面執行了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware三個接口的實現方法

2.調用每個BeanPostProcessor類的postProcessBeforeInitialization方法

其中ApplicationContextAwareProcessor#postProcessBeforeInitialization會調用invokeAwareInterfaces方法它會調用這幾種Aware的實現

EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware

3.invokeInitMethods執行初始化方法

設置Bean的初始化方法有兩種方法,一種是在xml或者@Bean指定init-method方法。另一種是讓bean實現InitializingBean接口重寫afterPropertiesSet()方法。

此方法中的執行邏輯是:

先執行InitializingBean接口的afterPropertiesSet方法,再進行init-method

4.調用每一個BeanPostProcessorpostProcessAfterInitialization方法

AbstractAutoProxyCreator就是一個BeanPostProcessor,它在這裏會被調用

7.最後一個是關於早期暴露的處理

通過getSingleton(String,false),從一級或者二級緩存裏取出已經暴露的實例

如果沒有早期暴露過則返回實例

如果有早期暴露:

原實例未經postProcessAfterInitialization代理(即在早期暴露的時候已經被代理過),則用早期暴露的實例返回

否則經過postProcessAfterInitialization代理,且被其他實例所依賴,即存在多個動態代理的循環依賴(如@Transactional和@Async一起使用),則拋出異常

二、整個getBean中各個擴展點的介紹

擴展點圖

可以看到擴展主要用到兩個大類的接口: 

1.BeanPostProcessor    作用於實例化、初始化階段的前後。實現了這些接口的Bean會切入到多個Bean的生命週期中,例如自動注入以及AOP的實現都和他們有關

2.Aware,所有的Aware方法都是在初始化方法之前被調用完

1.BeanPostProcessor中多個拓展點的調用時機

Spring中提供了若干個BeanPostProcessor接口(下稱BPP),BPP提供了在不同的時間點讓用戶對bean進行自定義調整的機會,大多數都在圖一用黃色泡泡特別標示了,有以下幾種BPP接口比較常用:

InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation:實例化前的操作

MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition:可對BeanDefinition添加額外的自定義配置

InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation:在populateBean前用戶可以手動注入一些屬性

InstantiationAwareBeanPostProcessor#postProcessPropertyValues:對屬性進行注入,例如配置文件加密信息在此解密後注入

BeanPostProcessor#postProcessBeforeInitialization:屬性注入後的一些額外操作

BeanPostProcessor#postProcessAfterInitialization:實例完成創建的最後一步,這裏也是一些BPP進行代理的時機

SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference:返回早期暴露的bean引用,一個典型的例子是循環依賴時如果有動態代理,需要在此先返回代理實例

2.Aware 

只調用一次的接口

又可以分爲兩類:

Aware類型的接口

生命週期接口

2.1Aware類型的接口

作用就是讓我們能夠拿到Spring容器中的一些資源。

Aware之前的名字就是可以拿到什麼資源,例如BeanNameAware可以拿到BeanName。

調用時機需要注意:所有的Aware方法都是在初始化階段之前調用的
Aware接口具體可以分爲兩組

Aware Group1

  1. BeanNameAware
  2. BeanClassLoaderAware
  3. BeanFactoryAware

Aware Group2

  1. EnvironmentAware
  2. EmbeddedValueResolverAware 實現該接口能夠獲取Spring EL解析器,用戶的自定義註解需要支持spel表達式的時候可以使用,非常方便。
  3. ResourceLoaderAware
  4. ApplicationEventPublisherAware
  5. MessageSourceAware
  6. ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware) 這幾個接口可能讓人有點懵,實際上這幾個接口可以一起記,其返回值實質上都是當前的ApplicationContext對象,因爲ApplicationContext是一個複合接口

可以看到並不是所有的Aware接口都使用同樣的方式調用。

Bean××Aware都是在代碼中直接調用的,

而ApplicationContext相關的Aware都是通過BeanPostProcessor類的ApplicationContextAwareProcessor#postProcessBeforeInitialization()實現的。

2.2簡單的兩個生命週期接口

至於剩下的兩個生命週期接口就很簡單了,實例化和屬性賦值都是Spring幫助我們做的,能夠自己實現的有初始化和銷燬兩個生命週期階段。

1.InitializingBean接口的afterPropertiesSet方法

對應生命週期的初始化階段,在源碼的invokeInitMethods(beanName, wrappedBean, mbd)方法中調用。
有一點需要注意,因爲Aware方法都是執行在初始化方法之前,所以可以在初始化方法中放心大膽的使用Aware接口獲取的資源,這也是我們自定義擴展Spring的常用方式。

除了實現InitializingBean接口之外還能通過註解或者xml配置的方式指定初始化方法,至於這幾種定義方式的調用順序其實沒有必要記。因爲這幾個方法對應的都是同一個生命週期,只是實現方式不同,我們一般只採用其中一種方式。

2.DisposableBean接口的destroy方法

 類似於InitializingBean,對應生命週期的銷燬階段

以ConfigurableApplicationContext#close()方法作爲入口,

實現是通過循環取所有實現了DisposableBean接口的Bean然後調用其destroy()方法 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章