上文中我們學習了bean加載的整個過程,我們知道從spring容器中獲取單例bean時會先從緩存嘗試獲取,如果緩存中不存在已經加載的單例bean就需要從頭開始bean的創建,而bean的創建過程是非常復雜的,本文就開始研究bean加載這部分的源碼。
1. bean創建流程分析
在Spring中bean加載的邏輯是在getSingleton的重載方法中實現的:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "'beanName' must not be null"); // 全局變量需要同步 synchronized (this.singletonObjects) { // 首先檢查對應的bean是否已經加載過,因為singleton模式就是復用已創建的bean,所以這一步是必須的 Object singletonObject = this.singletonObjects.get(beanName); // 如果為空才可以進行singleton的bean的初始化 if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while the singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } beforeSingletonCreation(beanName); boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<Exception>(); } try { // 初始化bean singletonObject = singletonFactory.getObject(); } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } // 加入緩存 addSingleton(beanName, singletonObject); } return (singletonObject != NULL_OBJECT ? singletonObject : null); } }
這里創建bean使用了回調方法(其實是匿名內部類),真正獲取單例bean的方法其實現邏輯是在ObjectFactory類型的實例singletonFactory的getObject()方法中實現的。Spring在創建單例前后還有一些准備及處理操作,包括如下內容:
- 檢查緩存是否已經加載過;
- 若沒有加載,則記錄beanName為正在加載狀態;
- 加載單例前記錄加載狀態;
- 通過調用參數傳入的ObjectFactory的個體Object方法實例化bean;
- 加載單例后的處理方法調用;
- 將結果記錄至緩存並刪除加載bean過程中所記錄的各種輔助狀態;
- 返回處理結果;
概括起來主要有下面幾方面:
1.1 加載單例前后處理加載狀態
在beforeSingletonCreation()方法中有一個很重要的操作:記錄加載狀態,也就是通過this.singletonsCurrentlyInCreation.add(beanName)將當前正要創建的bean記錄在緩存中,這樣便可以對循環依賴進行檢測。
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.containsKey(beanName) && this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) { throw new BeanCurrentlyInCreationException(beanName); } }
同記錄加載狀態相似,當bean加載結束后需要移除緩存中記錄的該bean的加載狀態記錄:
protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.containsKey(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } }
1.2 記錄加載結果
將結果記錄至緩存並刪除加載bean過程中所記錄的各種輔助狀態:
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
1.3 返回處理結果
雖然前面已經分析了加載bean的邏輯架構,但現在並沒有開始對bean加載功能的探索,前面提到過,bean加載邏輯其實是在匿名內部類ObjectFactory的getObject()方法中定義的:
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } });
ObjectFactory的核心部分其實只是調用了createBean()方法,也就是創建的bean的邏輯都在這里面,所以我們還需繼續尋找真理。
2. 准備創建bean
跟蹤了這么多Spring代碼,也發現了一些規律:一個真正干活的函數其實是以do開頭的,比如doGetObjectFromFactoryBean(),而容易給我們帶來錯覺的函數,比如getObjectFromFactoryBean(),其實只是從全局角度做了一些統籌工作。這個規則對於createBean()也不例外,我們就來看一下其中做了哪些准備工作:
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean '" + beanName + "'"); } // 根據設置的class屬性或者根據className來解析Class resolveBeanClass(mbd, beanName); // 驗證及准備覆蓋的方法 try { mbd.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // 給BeanPostProcessors一個機會返回代理的機會來替代真正的實例 Object bean = resolveBeforeInstantiation(beanName, mbd); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } Object beanInstance = doCreateBean(beanName, mbd, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; }
總結一下具體步驟:
- 根據設置的class屬性或者根據className來解析Class;
- 對override屬性進行標記及驗證;
- 應用初始化前的后處理器,解析指定bean是否存在初始化前的短路操作;
- 創建bean;
在Spring的配置里面是沒有諸如override-method之類的配置,那為什么還需要有override屬性進行標記及驗證這一步呢?這是因為在Spring配置中存在lookup-method和replace-method的,而這兩個配置的加載其實就是將配置統一存放在BeadDefinition中的methodOverrides屬性里,而這步操作就是針對這兩個配置的。
來看一下這幾個主要的步驟:
2.1 處理override屬性
這部分的邏輯是在AbstractBeanDefinition類的prepareMethodOverrides方法中:
public void prepareMethodOverrides() throws BeanDefinitionValidationException { // Check that lookup methods exists. MethodOverrides methodOverrides = getMethodOverrides(); if (!methodOverrides.isEmpty()) { for (MethodOverride mo : methodOverrides.getOverrides()) { prepareMethodOverride(mo); } } } protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException { // 獲取對應類中對應方法名的個數 int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName()); if (count == 0) { throw new BeanDefinitionValidationException( "Invalid method override: no method with name '" + mo.getMethodName() + "' on class [" + getBeanClassName() + "]"); } else if (count == 1) { // 標記MethodOverride暫未被覆蓋,避免參數類型檢查的開銷 mo.setOverloaded(false); } }
在Spring配置中存在lookup-method和replace-method兩個配置功能,而這兩個配置的加載其實就是將配置統一存放在BeanDefinition中的methodOverrides屬性里,這兩個功能實現原理其實是在bean實例化的時候如果檢測到存在methodOverrides屬性,會動態地為當前bean生成代理並使用對應的攔截器為bean做增強處理,這部分在創建bean部分會做詳細解析。
但是這里要提到的是,對於方法的匹配來講,如果一個類中存在若干個重載方法,那么,在函數調用及增強的時候還需要根據參數類型進行匹配,來最終確認當前調用的到底是哪個函數。但是,Spring將一部分匹配工作在這里完成了,如果當前類中的方法只有一個,那么就設置該方法沒有被重載,這樣在后續調用的時候便可以直接使用找到的方法,而不需要進行方法的參數匹配驗證了,而且還可以提前對方法存在性進行驗證,正可謂一石二鳥,這部分需要結合后面的邏輯來理解,現在不理解可以先忽略。
2.2 實例化的前置處理
在真正調用doCreate方法創建bean實例前使用了方法resolveBeforeInstantiation()對BeanDefinition中的屬性做一些前置處理。這里無論其中是否有相應的邏輯實現,我們都可以理解,因為真正邏輯實現前后留有處理函數也是可擴展的一種體現。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // Make sure bean class is actually resolved at this point. if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName); if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } mbd.beforeInstantiationResolved = (bean != null); } return bean; }
這里最重要的無疑是兩個方法applyBeanPostProcessorsBeforeInstantiation以及applyBeanPostProcessorsAfterInitialization,其實現非常簡單,無非是對后處理器中所有InstantiationAwareBeanPostProcessor類型的后處理器進行postProcessBeforeInstantiation方法和BeanPostProcessor的postProcessAfterInitialization方法的調用。
實例化前的后處理器應用
bean的實例化前調用,也就是將AbstractBeanDefinition轉換為BeanWrapper前的處理,這相當於給子類一個修改BeanDefinition的機會,也就是說當程序經過這個方法之后,bean可能已經不是我們認為的bean了,有可能是一個經過處理的代理bean,可能是通過cglib生成也可能是通過其他技術生成的,這個在后面涉及到AOP時會講到,現在我們只需要知道,在bean的實例化前會調用后處理器的方法進行處理:
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null; }
實例化后的后處理器應用
Spring中的規則是在bean初始化后盡可能保證將注冊的后處理器的postProcessAfterInitialization方法應用到該bean中,因為如果返回的bean不為空,那么便不會再次經歷普通bean的創建過程,所以只能在這里應用后處理器的postProcessAfterInitialization方法。
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { return result; } } return result; }
這里還有一點很重要,在該函數中還有一個短路判斷,這個很關鍵:
if(bean != null) { return bean; }
當經過前置處理后返回的結果如果不為空,那么會直接略過后續的Bean創建而直接返回,這個地方很容易被忽視,但是卻起着至關重要的作用,我們熟知的AOP功能就是基於這里的判斷的,后面關於AOP的文章中也會涉及到。
3. bean創建
當經歷過resolveBeforeInstantiation()方法后,如果創建了代理或者重寫了InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()方法並在方法postProcessBeforeInstantiation()中改變了bean,則直接返回就可以了,否則就需要進行常規bean的創建,這是在doCreateBean中完成的:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { // 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 != null ? instanceWrapper.getWrappedInstance() : null); Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { // 應用MergedBeanDefinitionPostProcessor applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } } // 是否需要提早曝光:單例&允許循環依賴&當前bean正在創建中,檢測循環依賴 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } // 為避免后期循環依賴,可以在bean初始化完成前將創建實例的ObjectFactory加入工廠 addSingletonFactory(beanName, new ObjectFactory<Object>() { public Object getObject() throws BeansException { // 對bean再一次依賴引用,主要應用SmartInstantiationAwareBeanPostProcessor // 其中我們熟知的AOP就是在這里將advice動態織入bean中,若沒有則直接返回bean,不做任何處理 return getEarlyBeanReference(beanName, mbd, bean); } }); } // Initialize the bean instance. Object exposedObject = bean; try { // 對bean進行填充,將各個屬性值注入,其中,可能存在依賴於其他bean的屬性,則會遞歸初始依賴bean populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { // 調用初始化方法,比如init-method exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); // earlySingletonReference只有在檢測到有循環依賴的情況下才會不為空 if (earlySingletonReference != null) { // 如果exposedObject沒有在初始化方法中被改變,也就是沒有被增強 if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length); for (String dependentBean : dependentBeans) { // 檢測依賴 if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } // 因為bean創建后其所依賴的bean一定是已經創建的, // actualDependentBeans不為空則表示當前bean創建后其依賴的bean卻沒有全部 // 創建完,也就是說存在循環依賴 if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } // Register bean as disposable. try { // 根據scope注冊bean registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
我們這里只簡單看看整個函數的概要思路,各個部分詳細邏輯留待后文分析:
1. 如果是單例則需要首先清除緩存。
2. 創建bean實例,即將BeanDefinition轉換為BeanWrapper。
轉換是一個復雜的過程,但是我們還是可以嘗試概括大致的功能,如下所示。
- 如果存在工廠方法則使用工廠方法進行初始化;
- 一個類有多個構造函數,每個構造函數都有不同的參數,所以需要根據參數鎖定構造函數並進行初始化;
- 如果及存在工廠方法也不存在帶有參數的構造函數,則使用默認的構造函數進行bean的實例化;
3. MergedBeanDefinitionPostProcessor的應用。
bean合並后的處理,Autowired注解正是通過此方法實現諸如類型的解析。
4. 依賴處理
在Spring會有循環依賴的情況,例如,當A中含有B的屬性,而B中又含有A的屬性時就會構成一個循環依賴,此時如果A和B都是單例,那么在Spring中的處理方式就是當創建B的時候,涉及自動注入A的步驟時,並不是直接去再次創建A,而是通過放入緩存中的ObjectFactory來創建實例,這樣就解決了循環依賴問題。
5. 屬性填充。將所有的屬性填充至bean的實例中。
6. 循環依賴檢查。
Spring中只在單例下才會解決循環依賴,而對於prototype的bean,Spring沒有好的解決辦法,唯一要做的就是拋出異常。在這個步驟里面會檢測已經加載的bean是否已經出現了依賴循環,並判斷是否需要拋出異常。
7. 注冊DisposableBean
如果配置了destroy-method,這里需要注冊以便於在銷毀時候調用。
8. 完成創建並返回。
4. 總結
本文先從全局角度分析了bean創建的整個流程,然后着重分析了Spring在bean創建之前所做的一些准備工作,包括override屬性處理、實例化前后對后處理器的應用,這些都只是一些全局性的統籌工作,之后又看了一下bean創建的實際過程,后面就要開始詳細分析bean的創建過程了,這個才是真正爬坡的開始。