讀完這篇文章你將會收穫到web
Spring
什麼時候將
bean
加入到第三級緩存和第一級緩存中
Spring
什麼時候回調各類
Aware
接口、
BeanPostProcessor
、
InitializingBean
等
相關文章面試
上兩篇文章 Spring 獲取單例流程(一) 和 Spring 獲取單例流程(二) 介紹了 getBean
前面的流程,今天最後的收尾,把後面的流程繼續一塊兒學習下緩存
// 我依賴的大哥都好了
// Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // 從三級緩存中移除這個 beanName 由於它可能被放進去了 由於放進去三級緩存能夠解決 setter 的循環依賴 destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } 複製代碼
若是咱們要建立的 bean
是一個單例,app
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) { // 看看第一級緩存中有沒有 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 將 beanName 加入到 singletonsCurrentlyInCreation 中,表明它正在建立中 beforeSingletonCreation(beanName); boolean newSingleton = false; try { singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { throw ex; } catch (BeanCreationException ex) { throw ex; } finally { // singletonsCurrentlyInCreation 從這裏面移除掉 afterSingletonCreation(beanName); } if (newSingleton) { // 加入緩存中 addSingleton(beanName, singletonObject); } } return singletonObject; } } 複製代碼
刪減了部分不重要的代碼,咱們大體來看看其流程編輯器
bean
了
beanName
加入到
singletonsCurrentlyInCreation
中,表明它正在建立中
ObjectFactory
的
getObject
方法得到一個
bean
singletonsCurrentlyInCreation
中移除、表明其已經建立完成了
全篇完結.終 !!!函數
其實真正的祕密藏身在參數的 ObjectFactory
中,從上面的流程中能夠宏觀的知道 Spring
建立 bean
的一個流程源碼分析
如今咱們在看看參數的 ObjectFactory
究竟幹啥子了post
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { ........... ........... try { // 真正 處理邏輯 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(xxxx); } } 複製代碼
幹活的仍是 do
開頭的大佬學習
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // 根據指定 bean 使用對應的策略建立新的實例、如工廠方法、構造函數自動注入、簡單初始化 instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); .......... ......... // 是否須要提早曝光、用來解決循環依賴的問題 // 是單例&容許循環依賴&正在建立中 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // 爲了不後期循環依賴、能夠在 bean 初始化前將建立實例的ObjectFactory 加入工廠 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { // 填充屬性 populateBean(beanName, mbd, instanceWrapper); // 調用初始方法 exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { ......... } ........ ....... return exposedObject; } 複製代碼
上面的流程大體就是this
createBeanInstance
這個方法根據你的配置以及你的 bean
的狀況選擇出一種建立 bean
的方法、多是工廠方法、多是某個構造函數、多是默認的構造函數。這裏包含了當一個構造函數的參數是另外一個 bean
的時候、它會經過 getBean
的方法獲取這個參數的 bean
而後將建立好的 bean
加入到第三級緩存中,默認設置咱們是容許循環依賴的
populateBean
方法就是咱們填充屬性了、若是你依賴的其餘 Spring
的其餘 bean
是經過這種方式注入的話(autowireByName
autowireByType
)、就是在這一步注入的了,他獲取其餘 bean
也是經過 getBean
的方式獲取
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
......... ......... if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } ......... ......... } 複製代碼
initializeBean
則是調用咱們的各類回調接口、Aware
類型的、BeanPostProcessor
、InitializingBean
、自定義初始化函數
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> {。 // 調用各類 Aware 接口 invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { // 調用各類 Aware 接口 invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // 調用 BeanPostProcessor postProcessBeforeInitialization wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // 調用 InitializingBean 、自定義的初始化方法 invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { // 調用 BeanPostProcessor postProcessAfterInitialization wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; } 複製代碼
其實總體的流程就差很少了
name
找出對應的
beanName
、不管這個
name
是別名或者是一個
factoryBean
的
beanName
beanName
對象
singletonObjects
中看看有沒有
earlySingletonObjects
singletonFactories
中看看有沒有
bean
、那麼咱們仍是須要處理一下這個
bean
Spring
緩存中返回的
bean
是
factoryBean
、而用戶也想要的是一個
beanFactory
(參數
name
中的前綴是
&
)、那麼咱們直接返回
Spring
緩存中返回的
bean
是普通的
bean
、而用戶也想要的是一個普通的
bean
、那麼就直接返回
Spring
緩存中返回的
bean
是一個
factoryBean
、而用戶想要的是一個普通的
bean
、那麼咱們就要從
factoryBean
中獲取這個
bean
factoryBean
中獲取這個
bean
的過程當中、須要調用到前置處理、後置處理和咱們經常使用的接口回調
BeanPostProcessor
bean
、則判斷是不是
prototype
類型而且循環依賴
bean
beanName
對應的
beanDefinition
找出其依賴的
beanName
beanName
與 依賴的
beanName
是否循環依賴、沒有則註冊其依賴關係並調用
getBean
方法去建立依賴的
beanName
beanName
加入到
singletonsCurrentlyInCreation
中
singletonsCurrentlyInCreation
中移除、表明其已經建立完成了
bean
給調用方
其實整體的流程仍是不算複雜把、咱們也能夠從中收穫到一些東西。其實咱們最關心也是面試最常問的一個問題就是、Spring 如何解決循環依賴的問題、感興趣的能夠看看這篇文章公衆號內的 Spring 循環依賴
這篇文章