一、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.調用每一個BeanPostProcessor的postProcessAfterInitialization方法
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
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
Aware Group2
- EnvironmentAware
- EmbeddedValueResolverAware 實現該接口能夠獲取Spring EL解析器,用戶的自定義註解需要支持spel表達式的時候可以使用,非常方便。
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- 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()方法 。