spring源碼學習之bean的加載(一)


  對XML文件的解析基本上已經大致的走了一遍,雖然沒有能吸收多少,但是腦子中總是有些印象的,接下來看下spring中的bean的加載,這個比xml解析復雜的多。
這個加載,在我們使用的時候基本上是:
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactory.xml"));
MyTestBean bean = (MyTestBean) beanFactory.getBean("myTestBean"); // 這個是bean的加載的使用

一、總體掌握

看看spring中的代碼是如何實現的:
這個是在org.springframework.beans.factory.support包下的AbstractBeanFactory類

  1 @Override
  2 public Object getBean(String name) throws BeansException {
  3     return doGetBean(name, null, null, false);
  4 }
  5 
  6 /**
  7  * Return an instance, which may be shared or independent, of the specified bean.
  8  * @param name the name of the bean to retrieve
  9  * @param requiredType the required type of the bean to retrieve
 10  * @param args arguments to use when creating a bean instance using explicit arguments
 11  * (only applied when creating a new instance as opposed to retrieving an existing one)
 12  * @param typeCheckOnly whether the instance is obtained for a type check,
 13  * not for actual use
 14  * @return an instance of the bean
 15  * @throws BeansException if the bean could not be created
 16  */
 17 @SuppressWarnings("unchecked")
 18 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
 19         @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
 20 
 21     // 提取對應的beanName
 22     final String beanName = transformedBeanName(name);
 23     Object bean;
 24     
 25     /**
 26      * 檢查緩存中或者實例工廠中是否有對應的實例
 27      * 為什么會首先使用這段代碼呢?
 28      * 因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候是為了避免循環依賴
 29      *spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光
 30      * 也就是將ObjectFactory加入緩存中,一旦下個bean創建的時候需要依賴上個bean,則直接使用ObjectFactory  
 31      */
 32     // Eagerly check singleton cache for manually registered singletons.
 33     // 直接嘗試從緩存中獲取或者singletonFactories中ObjectFactory中獲取
 34     Object sharedInstance = getSingleton(beanName);
 35     if (sharedInstance != null && args == null) {
 36         if (logger.isDebugEnabled()) {
 37             if (isSingletonCurrentlyInCreation(beanName)) {
 38                 logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
 39                         "' that is not fully initialized yet - a consequence of a circular reference");
 40             }
 41             else {
 42                 logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
 43             }
 44         }
 45         // 返回對應的實例,有時候存在諸如BeanFactory的情況並不是直接返回實例本身而是返回指定方法返回的實例
 46         bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
 47     }
 48 
 49     else {
 50         // Fail if we're already creating this bean instance:
 51         // We're assumably within a circular reference.
 52         /**
 53          * 只有在單例的情況下才會嘗試解決循環依賴,原型模式下,
 54          * 如果存在A中有B的屬性,B中有A的屬性,那么當依賴注入的時候,就會產生
 55          * 當A還未創建完的時候,創建B,再次返回創建A,造成循環依賴,下面這種錯誤,拋出異常
 56          */
 57         if (isPrototypeCurrentlyInCreation(beanName)) {
 58             throw new BeanCurrentlyInCreationException(beanName);
 59         }
 60 
 61         // Check if bean definition exists in this factory.
 62         BeanFactory parentBeanFactory = getParentBeanFactory();
 63         // 在parentBeanFactory中檢測
 64         if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 65             // Not found -> check parent.
 66             String nameToLookup = originalBeanName(name);
 67             // 遞歸到BeanFactory中查找
 68             if (parentBeanFactory instanceof AbstractBeanFactory) {
 69                 return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
 70                         nameToLookup, requiredType, args, typeCheckOnly);
 71             }
 72             else if (args != null) {
 73                 // Delegation to parent with explicit args.
 74                 return (T) parentBeanFactory.getBean(nameToLookup, args);
 75             }
 76             else {
 77                 // No args -> delegate to standard getBean method.
 78                 return parentBeanFactory.getBean(nameToLookup, requiredType);
 79             }
 80         }
 81         
 82         // 如果不是僅僅做類型檢查則是創建bean,這里需要記錄
 83         if (!typeCheckOnly) {
 84             markBeanAsCreated(beanName);
 85         }
 86 
 87         try {
 88             // 將存儲XML配置文件GenericBeanDefinition轉換為RootBeanDefinition
 89             // BeanName是子Bean的話同時會合並父類的相關屬性
 90             final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 91             checkMergedBeanDefinition(mbd, beanName, args);
 92 
 93             // Guarantee initialization of beans that the current bean depends on.
 94             String[] dependsOn = mbd.getDependsOn();
 95             // 若存在依賴則需要遞歸實例化依賴bean
 96             if (dependsOn != null) {
 97                 for (String dep : dependsOn) {
 98                     if (isDependent(beanName, dep)) {
 99                         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
100                                 "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
101                     }
102                     // 緩存依賴調用
103  registerDependentBean(dep, beanName);
104                     try {
105                         getBean(dep);
106                     }
107                     catch (NoSuchBeanDefinitionException ex) {
108                         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
109                                 "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
110                     }
111                 }
112             }
113 
114             // Create bean instance.
115             // 實例化依賴的bean后便可以實例化mbd本身了
116             // singleton模式的創建
117             if (mbd.isSingleton()) {
118                 sharedInstance = getSingleton(beanName, () -> {
119                     try {
120                         return createBean(beanName, mbd, args);
121                     }
122                     catch (BeansException ex) {
123                         // Explicitly remove instance from singleton cache: It might have been put there
124                         // eagerly by the creation process, to allow for circular reference resolution.
125                         // Also remove any beans that received a temporary reference to the bean.
126                         destroySingleton(beanName);
127                         throw ex;
128                     }
129                 });
130                 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
131             }
132             // Prototype模式創建
133             else if (mbd.isPrototype()) {
134                 // It's a prototype -> create a new instance.
135                 Object prototypeInstance = null;
136                 try {
137                     beforePrototypeCreation(beanName);
138                     prototypeInstance = createBean(beanName, mbd, args);
139                 }
140                 finally {
141                     afterPrototypeCreation(beanName);
142                 }
143                 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
144             }
145             // 指定scope上實例化bean
146             else {
147                 String scopeName = mbd.getScope();
148                 final Scope scope = this.scopes.get(scopeName);
149                 if (scope == null) {
150                     throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
151                 }
152                 try {
153                     Object scopedInstance = scope.get(beanName, () -> {
154                         beforePrototypeCreation(beanName);
155                         try {
156                             return createBean(beanName, mbd, args);
157                         }
158                         finally {
159                             afterPrototypeCreation(beanName);
160                         }
161                     });
162                     bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
163                 }
164                 catch (IllegalStateException ex) {
165                     throw new BeanCreationException(beanName,
166                             "Scope '" + scopeName + "' is not active for the current thread; consider " +
167                             "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
168                             ex);
169                 }
170             }
171         }
172         catch (BeansException ex) {
173             cleanupAfterBeanCreationFailure(beanName);
174             throw ex;
175         }
176     }
177 
178     // Check if required type matches the type of the actual bean instance.
179     // 檢查需要的類型是否符合bean的實例類型
180     if (requiredType != null && !requiredType.isInstance(bean)) {
181         try {
182             T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
183             if (convertedBean == null) {
184                 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
185             }
186             return convertedBean;
187         }
188         catch (TypeMismatchException ex) {
189             if (logger.isDebugEnabled()) {
190                 logger.debug("Failed to convert bean '" + name + "' to required type '" +
191                         ClassUtils.getQualifiedName(requiredType) + "'", ex);
192             }
193             throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
194         }
195     }
196     return (T) bean;
197 }

(1)轉換對應的beanName
這里傳入的參數name並不一定是beanName,可能是別名,也可能是FactoryBean,所以進行一系類的解析,這些解析內容如下
1)去除FactoryBean的修飾符,也就是name="&aa",那么首先會去除&,而使name=aa
2)取指定別名所表示的最終的beanName

(2)嘗試從緩存中加載單例
單例在spring的同一個容器內只會被創建一次,后續在獲取bean,就直接從單例緩存中獲取了,當然,這里也只是嘗試加載,
首先嘗試從緩存中加載,如果加載不成功則再次嘗試從singletonFactories中加載。因為在創建單例bean的時候會存在依賴注入的情況
而在創建依賴的時候為了避免循環依賴,在spring中創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光加入
到緩存中,一旦下一個bean創建的時候需要依賴上一個bean則直接使用ObjectFactory

(3)bean的實例化
如果緩存中得到了bean的原始狀態,則需要對bean進行實例化,緩存中的記錄只是最原始的bean狀態,並不一定是我們最終想要的bean,
舉個例子,假如我們想對工廠bean進行處理,那么這里得到的是工廠bean的初始狀態,但是我們真正想要的是工廠bean定義的factory-method
方法中返回的bean,而getObjectForBeanInstance就是完成這個工作的

(4)原型模式的依賴檢查
只有在單例情況下才會嘗試解決循環依賴,如果存在A中有B的屬性,B中有A的屬性,那么當依賴注入的時候,就會產生當A還沒創建完成的時候,因為
對B的創建再次返回創建A,造成循環依賴,也就是(isPrototypeCurrentlyInCreation(beanName))為true的情況

(5)檢測parentBeanFactory
從代碼上看,如果緩存沒有數據的話,直接轉到父類工廠上去加載了,這是為什么?可能我們忽略了
parentBeanFactory != null && !containsBeanDefinition(beanName)這里面判斷條件,parentBeanFactory != null,parentBeanFactory如果為空,
其他一切都是浮雲,但是還有一個條件,!containsBeanDefinition(beanName),它是在檢測如果當前加載的XML配置文件中,不包含beanName多對應的
配置,只能去parentBeanFactory中嘗試,然后再去遞歸的調用遞歸方法

(6)將存儲XML配置文件GenericBeanDefinition轉換為RootBeanDefinition
因為從XML配置文件中讀取到的bean信息存儲在GenericBeanDefinition中,但是所有的bean的后續處理都是針對於RootBeanDefinition,
所以這里需要進行一個轉換,轉換的同時,如果父類bean不為空的話,則會一並合並父類屬性

(7)尋找依賴
因為bean的初始化過程很肯能用到某些屬性,而某些屬性可能是動態配置的,並且配置成依賴其他的bean,那么這個時候必須先加載依賴的bean,
spring的加載順序中,在初始化一個bean的時候,首先會初始化這個bean所對應的依賴

(8)針對不同的scope進行bean的創建
spring根據不同的配置進行不同的初始化策略,默認的是singleton

(9)類型轉換
程序到這里已經基本結束了,通常對該方法的調用參數requireType是為空的,但是可能會存在這樣的情況,返回的bean其實是個String,但是
requireType卻傳入的是Integer類型,那么這時候本步驟就起作用了,他的功能是將返回的bean轉換為requireType所指定的類型。

二、剝離,逐一分析

1、FactoryBean的使用

一般情況下,spring通過反射機制,利用bean的class屬性指定實現類來實例化bean。在某些情況下,實例化bean的過程比較復雜,按照傳統的方式,
則需要在bean的配置中提供大量的配置信息,配置方式的靈活性是受限的,spring為此提供了一個org.springframework.beans.factory.FactoryBean
工廠類接口,用戶可以實現該接口定制實例化bean的邏輯

FactoryBean接口對於spring來說,占有重要地位,spring自身就提供了70多個FactoryBean的實現,從spring 3.0開始,FactoryBean開始支持泛型
接口聲明為:

1 public interface FactoryBean<T> {
2     T getObject() throws Exception;
3     Class<?> getObjectType();
4     default boolean isSingleton() {
5         return true;
6     }
7 }

接口中定義的三個方法:
1)T getObject():返回由FactoryBean創建的bean實例,如果isSignleton()返回的是true,則該實例會方放到spring容器中單實例緩存池中
2)default boolean isSingleton():判斷創建bean的scope
3)Class<?> getObjectType():返回創建bean的類型

2、緩存中獲取單例bean

單例在spring的同一容器中只會被創建一次,然后再獲取bean直接從單例緩存中獲取,當然,這里也只是嘗試加載,首先嘗試從緩存中加載,
然后再次嘗試從singletonFactories中加載,因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候為了避免循環依賴,
spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建的時候依賴上個bean
則直接使用ObjectFactory
下面的額源碼是在org.springframework.beans.factory.support包下DefaultSingletonBeanRegistry中

 1 @Override
 2 @Nullable
 3 public Object getSingleton(String beanName) {
 4     return getSingleton(beanName, true);
 5 }
 6 
 7 /**
 8  * Return the (raw) singleton object registered under the given name.
 9  * <p>Checks already instantiated singletons and also allows for an early
10  * reference to a currently created singleton (resolving a circular reference).
11  * @param beanName the name of the bean to look for
12  * @param allowEarlyReference whether early references should be created or not
13  * @return the registered singleton object, or {@code null} if none found
14  */
15 @Nullable
16 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
17     // 檢查緩存中是否存在實例
18     Object singletonObject = this.singletonObjects.get(beanName);
19     if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
20         // 如果為空,則鎖定全局變量並進行處理
21         synchronized (this.singletonObjects) {
22             // 如果此bean正在加載則不處理
23             singletonObject = this.earlySingletonObjects.get(beanName);
24             if (singletonObject == null && allowEarlyReference) {
25                 // ObjectFactory初始化策略存儲在singletonFactories
26                 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
27                 if (singletonFactory != null) {
28                     // 調用預先設定好的getObject()方法
29                     singletonObject = singletonFactory.getObject();
30                     // 記錄在緩存中earlySingletonObjects和singletonFactories互斥
31                     this.earlySingletonObjects.put(beanName, singletonObject);
32                     this.singletonFactories.remove(beanName);
33                 }
34             }
35         }
36     }
37     return singletonObject;
38 }

這個方法首先嘗試從singletonObjects里面獲取實例,如果獲取不到,再從earlySingletonObjects中獲取,如果還獲取不到,嘗試從
singletonFactories中獲取beanName對應的ObjectFactory,然后調用這個ObjectFactory的getObject()來創建bean,並放到earlySingletonObjects中去,
並且從singletonFactories中remove掉ObjectFactory,而對於后續的所有內存操作都只為了循環依賴檢測時候使用,這里有幾個不同的map:
singletonObjects:用於保存BeanName和創建bean實例之間的關系,bean name -> bean instance
singletonFactories:用於保存BeanName和創建bean工廠之間的關系,bean name -> ObjectFactory
earlySingletonObjects:用於保存BeanName和創建bean實例之間的關系,與ingletonObjects不同的是,當一個單例bean被放到這里面后,那么當bean
還在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環引用
registeredSingletons:用來保存所有當前已存在的bean

3、從bean的實例中獲取對象

在getBean()方法中,getObjectForBeanInstance是個高頻使用的方法,無論是從緩存中獲取bean還是根據不同的scope策略加載bean,總之,得到bean
的實例后,我們第一步要做的就是調用這個方法來檢測一下正確性,其實就是用於檢測當前bean是否是FactoryBean類型的bean,如果是,那么需要調用該
bean對應的FactoryBean實例中的getObject()作為返回值

無論是從緩存中獲取到bean還是從不同的scope策略中加載的bean都是最原始的bean狀態,並不一定是我們最終想要的bean,而getObjectForBeanInstance
方法就是完成這個工作的
該方法是在org.springframework.beans.factory.support包下的AbstractBeanFactory類:

 1 protected Object getObjectForBeanInstance(
 2         Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
 3 
 4     // Don't let calling code try to dereference the factory if the bean isn't a factory.
 5     // 如果指定的name是工廠相關(以&為前綴)且beanInstance又不是FactoryBean類型則驗證不通過
 6     if (BeanFactoryUtils.isFactoryDereference(name)) {
 7         if (beanInstance instanceof NullBean) {
 8             return beanInstance;
 9         }
10         if (!(beanInstance instanceof FactoryBean)) {
11             throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
12         }
13     }
14 
15     // Now we have the bean instance, which may be a normal bean or a FactoryBean.
16     // If it's a FactoryBean, we use it to create a bean instance, unless the
17     // caller actually wants a reference to the factory.
18     // 現在我們有了一個bean的實例,這個實例可能是正常的bean或者是FactoryBean類型的
19     // 如果是FactoryBean我們使用它創建實例
20     // 但是如果用戶想要直接獲取工廠實例而不是工廠的getObject()方法對應的實例,那么傳入的name應該加入前綴&
21     if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
22         return beanInstance;
23     }
24 
25     Object object = null;
26     if (mbd == null) {
27         // 嘗試從緩存中加載bean
28         object = getCachedObjectForFactoryBean(beanName);
29     }
30     if (object == null) {
31         // Return bean instance from factory.
32         // 到這里已經明確知道beanInstance一定是FactoryBean
33         FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
34         // Caches object obtained from FactoryBean if it is a singleton.
35         // containsBeanDefinition檢測beanDefinitionMap中也就是所有已經記載的類中檢測是否定義beanName
36         if (mbd == null && containsBeanDefinition(beanName)) {
37             // 將存儲XML配置文件的GernericBeanDefinition轉換為RootBeanDefinition
38             // 如果指定BeanName 是子bean的話同時合並父類的相關屬性
39             mbd = getMergedLocalBeanDefinition(beanName);
40         }
41         // 是否是用戶定義的,而不是應用程序本身定義的
42         boolean synthetic = (mbd != null && mbd.isSynthetic());
43         object = getObjectFromFactoryBean(factory, beanName, !synthetic);
44     }
45     return object;
46 }

這個方法其實大部分代碼是在做一些功能性判斷,真正的核心的代碼交給了getObjectFromFactoryBean()方法來處理
此方法是在org.springframework.beans.factory.support包下的FactoryBeanRegistrySupport類
這個和作者在書中的源碼有些不同的地方,應該是做了一些優化,注意一下這個地方,有些源碼還是不懂為啥那么做

 1 /**
 2  * Obtain an object to expose from the given FactoryBean.
 3  * @param factory the FactoryBean instance
 4  * @param beanName the name of the bean
 5  * @param shouldPostProcess whether the bean is subject to post-processing
 6  * @return the object obtained from the FactoryBean
 7  * @throws BeanCreationException if FactoryBean object creation failed
 8  * @see org.springframework.beans.factory.FactoryBean#getObject()
 9  */
10 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
11     // 如果是單例模式
12     if (factory.isSingleton() && containsSingleton(beanName)) {
13         synchronized (getSingletonMutex()) {
14             // 從緩存中獲取bean實例
15             Object object = this.factoryBeanObjectCache.get(beanName);
16             if (object == null) {
17                 // 從工廠bean中獲取bean實例
18                 object = doGetObjectFromFactoryBean(factory, beanName);
19                 // Only post-process and store if not put there already during getObject() call above
20                 // (e.g. because of circular reference processing triggered by custom getBean calls)
21                 Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
22                 if (alreadyThere != null) {
23                     object = alreadyThere;
24                 }
25                 else {
26                     if (shouldPostProcess) {
27                         if (isSingletonCurrentlyInCreation(beanName)) {
28                             // Temporarily return non-post-processed object, not storing it yet..
29                             return object;
30                         }
31  beforeSingletonCreation(beanName);
32                         try {
33                             object = postProcessObjectFromFactoryBean(object, beanName);
34                         }
35                         catch (Throwable ex) {
36                             throw new BeanCreationException(beanName,
37                                     "Post-processing of FactoryBean's singleton object failed", ex);
38                         }
39                         finally {
40  afterSingletonCreation(beanName);
41                         }
42                     }
43                     if (containsSingleton(beanName)) {
44                         this.factoryBeanObjectCache.put(beanName, object);
45                     }
46                 }
47             }
48             return object;
49         }
50     }
51     else {
52         Object object = doGetObjectFromFactoryBean(factory, beanName);    
53         if (shouldPostProcess) {
54             // bean需要做后續處理
55             try {
56                 object = postProcessObjectFromFactoryBean(object, beanName);
57             }
58             catch (Throwable ex) {
59                 throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
60             }
61         }
62         return object;
63     }
64 }

從工廠中獲取bean實例的代碼在doGetObjectFromFactoryBean()方法中,來看看
此方法是在org.springframework.beans.factory.support包下的FactoryBeanRegistrySupport類

 1 /**
 2  * Obtain an object to expose from the given FactoryBean. --> 獲得一個bean實例從所給的工廠bean中
 3  * @param factory the FactoryBean instance
 4  * @param beanName the name of the bean
 5  * @return the object obtained from the FactoryBean
 6  * @throws BeanCreationException if FactoryBean object creation failed
 7  * @see org.springframework.beans.factory.FactoryBean#getObject()
 8  */
 9 private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
10         throws BeanCreationException {
11 
12     Object object;
13     try {
14         // 需要權限驗證 access是權限的意思
15         if (System.getSecurityManager() != null) {
16             AccessControlContext acc = getAccessControlContext();
17             try {
18                 object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
19             }
20             catch (PrivilegedActionException pae) {
21                 throw pae.getException();
22             }
23         }
24         else {
25             // 在工廠中創建bean實例
26             object = factory.getObject();
27         }
28     }
29     catch (FactoryBeanNotInitializedException ex) {
30         throw new BeanCurrentlyInCreationException(beanName, ex.toString());
31     }
32     catch (Throwable ex) {
33         throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
34     }
35 
36     // Do not accept a null value for a FactoryBean that's not fully
37     // initialized yet: Many FactoryBeans just return null then.
38     if (object == null) {
39         if (isSingletonCurrentlyInCreation(beanName)) {
40             throw new BeanCurrentlyInCreationException(
41                     beanName, "FactoryBean which is currently in creation returned null from getObject");
42         }
43         object = new NullBean();
44     }
45     return object;
46 }

這個能得到實例化的bean了,但是根據shouldPostProcess來進行后續的bean處理,走的是postProcessObjectFromFactoryBean()方法
org.springframework.beans.factory.support包下的FactoryBeanRegistrySupport類,這個是抽象類,找到實現該方法的類,那就是
org.springframework.beans.factory.support包下的AbstractAutowireCapableBeanFactory類,看一下這個類中源碼實現:

 1 /**
 2  * Applies the {@code postProcessAfterInitialization} callback of all
 3  * registered BeanPostProcessors, giving them a chance to post-process the
 4  * object obtained from FactoryBeans (for example, to auto-proxy them).
 5  * @see #applyBeanPostProcessorsAfterInitialization
 6  */
 7 @Override
 8 protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
 9     return applyBeanPostProcessorsAfterInitialization(object, beanName);
10 }
11 
12 @Override
13 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
14         throws BeansException {
15 
16     Object result = existingBean;
17     for (BeanPostProcessor processor : getBeanPostProcessors()) {
18         Object current = processor.postProcessAfterInitialization(result, beanName);
19         if (current == null) {
20             return result;
21         }
22         result = current;
23     }
24     return result;
25 }

對於后續處理操作,作者在這里沒有詳細介紹,后續會有詳細介紹,這里就不詳細講解了,我也沒法記下來,只能跟着作者的思路來進行探索了,
這里作者提出了一條總結:spring獲取bean的規則只有一條:盡可能保證所有bean初始化后都會調用注冊的BeanPostProcessor的postProcessAfterInitialization
方法進行處理,也就是上面方法中的Object current = processor.postProcessAfterInitialization(result, beanName);這一行代碼,可以針對此特性設計自己的
設計邏輯

4、獲取單例

之前我們講解了從緩存中獲取單例的過程,那么,如果緩存中不存在已經加載的單例bean,就需要從頭開始bean的加載過程了,而spring中使用了
getSingleton()的重載方法實現bean的加載過程

 1 /**
 2  * Return the (raw) singleton object registered under the given name,
 3  * creating and registering a new one if none registered yet.
 4  * @param beanName the name of the bean
 5  * @param singletonFactory the ObjectFactory to lazily create the singleton
 6  * with, if necessary
 7  * @return the registered singleton object
 8  */
 9 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
10     Assert.notNull(beanName, "Bean name must not be null");
11     // 全局變量需要同步
12     synchronized (this.singletonObjects) {
13         // 首先檢查對應的bean是否已經加載過,因為singleton模式其實就是復用以創建的bean,所以這一步是必須的
14         Object singletonObject = this.singletonObjects.get(beanName);
15         // 如果為空才可以進行singleton的bean的初始化
16         if (singletonObject == null) {
17             if (this.singletonsCurrentlyInDestruction) {
18                 throw new BeanCreationNotAllowedException(beanName,
19                         "Singleton bean creation not allowed while singletons of this factory are in destruction " +
20                         "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
21             }
22             if (logger.isDebugEnabled()) {
23                 logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
24             }
25  beforeSingletonCreation(beanName);
26             boolean newSingleton = false;
27             boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
28             if (recordSuppressedExceptions) {
29                 this.suppressedExceptions = new LinkedHashSet<>();
30             }
31             try {
32                 // 初始化bean
33                 singletonObject = singletonFactory.getObject();
34                 newSingleton = true;
35             }
36             catch (IllegalStateException ex) {
37                 // Has the singleton object implicitly appeared in the meantime ->
38                 // if yes, proceed with it since the exception indicates that state.
39                 singletonObject = this.singletonObjects.get(beanName);
40                 if (singletonObject == null) {
41                     throw ex;
42                 }
43             }
44             catch (BeanCreationException ex) {
45                 if (recordSuppressedExceptions) {
46                     for (Exception suppressedException : this.suppressedExceptions) {
47                         ex.addRelatedCause(suppressedException);
48                     }
49                 }
50                 throw ex;
51             }
52             finally {
53                 if (recordSuppressedExceptions) {
54                     this.suppressedExceptions = null;
55                 }
56  afterSingletonCreation(beanName);
57             }
58             if (newSingleton) {
59                 // 加入緩存中
60  addSingleton(beanName, singletonObject);
61             }
62         }
63         return singletonObject;
64     }
65 }

上述代碼中其實使用了回調方法,使得程序可以在單例創建的前后做一些准備及處理操作,而真正的獲取單例bean的方法其實並不是在此方法中實現,
其邏輯是在ObjectFactory類型的實例singletonFactory中實現的,而這些准備和處理操作包括如下:
(1)檢查緩存中是否已經加載過
(2)若沒有加載,則記錄beanName的正在加載狀態
(3)加載單例前記錄加載狀態

可能你會覺得beforeSingletonCreation方法是個空實現,里面沒有任何邏輯,但其實不是,這個函數中做了一個很重要的操作:記錄加載狀態,也就是
通過this.singletonsCurrentlyInCreation.add(beanName)將當前正要創建的bean記錄在緩存中,這樣就可以對循環依賴進行檢測 同一個類中

1 protected void beforeSingletonCreation(String beanName) {
2     if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
3         throw new BeanCurrentlyInCreationException(beanName);
4     }
5 }

(4)通過調用參數傳入的ObjectFactory的個體Object方法實例化bean
(5)加載單例后的處理方法調用
同步驟3的記錄加載狀態相似,當bean加載結束后需要移除緩存中對該bean的正在加載狀態的記錄,同一個類中

1 protected void afterSingletonCreation(String beanName) {
2     if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
3         throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
4     }
5 }

(6)將結果記錄至緩存並刪除加載bean過程中所記錄的各種輔助狀態 同一個類中

1 protected void addSingleton(String beanName, Object singletonObject) {
2     synchronized (this.singletonObjects) {
3         this.singletonObjects.put(beanName, singletonObject);
4         this.singletonFactories.remove(beanName);
5         this.earlySingletonObjects.remove(beanName);
6         this.registeredSingletons.add(beanName);
7     }
8 }

(7)返回處理結果
雖然我們了解了加載bean的邏輯架構,但是現在我們並沒有開始對bean加載功能進行探索,之前提到過,bean的加載邏輯實在傳入的ObjectFactory類型的參數
singletonFactory中定義的,我們反推參數的獲取,得到以下代碼:這我就不會往回反推參數,全局搜索的。。。
這段代碼是在org.springframework.beans.factory.support包下AbstractBeanFactory類中,doGetBean()方法

 1 sharedInstance = getSingleton(beanName, () -> {
 2     try {
 3         return createBean(beanName, mbd, args);
 4     }
 5     catch (BeansException ex) {
 6         // Explicitly remove instance from singleton cache: It might have been put there
 7         // eagerly by the creation process, to allow for circular reference resolution.
 8         // Also remove any beans that received a temporary reference to the bean.
 9         destroySingleton(beanName);
10         throw ex;
11     }
12 });

ObjectFactory的核心部分只調用了createBean()方法,繼續探索createBean()

5、准備創建bean
這里作者提出了一點在探索spring源碼的過程中的一點規律:一個真正干活的函數其實是以do開頭的,比如doGetObjectFromFactoryBean,而給我們錯覺的函數
getObjectFromFactoryBean,其實只是從全局角度去做一些統籌工作,這個規則對createBean也不例外,看createBean如何統籌工作:

 1 /**
 2  * Central method of this class: creates a bean instance,
 3  * populates the bean instance, applies post-processors, etc.
 4  * @see #doCreateBean
 5  */
 6 @Override
 7 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
 8         throws BeanCreationException {
 9 
10     if (logger.isDebugEnabled()) {
11         logger.debug("Creating instance of bean '" + beanName + "'");
12     }
13     RootBeanDefinition mbdToUse = mbd;
14 
15     // Make sure bean class is actually resolved at this point, and
16     // clone the bean definition in case of a dynamically resolved Class
17     // which cannot be stored in the shared merged bean definition.
18     // 鎖定class,根據設置的class屬性或者根據beanName來解析Class,具體在實現邏輯在resolveBeanClass()方法中
19     Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
20     if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
21         mbdToUse = new RootBeanDefinition(mbd);
22         mbdToUse.setBeanClass(resolvedClass);
23     }
24 
25     // Prepare method overrides.
26     // 驗證及准備覆蓋方法
27     try {
28         // 
29         mbdToUse.prepareMethodOverrides();
30     }
31     catch (BeanDefinitionValidationException ex) {
32         throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
33                 beanName, "Validation of method overrides failed", ex);
34     }
35 
36     try {
37         // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
38         // 給BeanPostProcessors一個機會來返回代理來替代真正的實例
39         Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
40         if (bean != null) {
41             return bean;
42         }
43     }
44     catch (Throwable ex) {
45         throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
46                 "BeanPostProcessor before instantiation of bean failed", ex);
47     }
48 
49     try {
50         // 真正的創建bean的代碼在這個方法中
51         Object beanInstance = doCreateBean(beanName, mbdToUse, args);
52         if (logger.isDebugEnabled()) {
53             logger.debug("Finished creating instance of bean '" + beanName + "'");
54         }
55         return beanInstance;
56     }
57     catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
58         // A previously detected exception with proper bean creation context already,
59         // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
60         throw ex;
61     }
62     catch (Throwable ex) {
63         throw new BeanCreationException(
64                 mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
65     }
66 }

來看下具體步驟和功能
(1)根據設置的class屬性或者是beanName來解析Class
(2)對override屬性進行標記和驗證
這個其實spring中沒有override-method這樣的配置,但是spring是存在lookup-method和replace-method的,而這兩個配置的加載其實
就是將配置統一存放到BeanDefinition中的methodOverride屬性里,這個函數的操作其實就是針對這兩個屬性
(3)應用初始化前的后處理器,解析指定bean是否存在初始化前的短路操作
(4)創建bean

5.1 處理override屬性

prepareMethodOverrides()方法在org.springframework.beans.factory.support包下的AbstractBeanDefinition類中

 1 public void prepareMethodOverrides() throws BeanDefinitionValidationException {
 2     // Check that lookup methods exists.
 3     if (hasMethodOverrides()) {
 4         Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
 5         synchronized (overrides) {
 6             for (MethodOverride mo : overrides) {
 7  prepareMethodOverride(mo);
 8             }
 9         }
10     }
11 }
12 
13 //繼續看prepareMethodOverride(mo)方法的源碼,在同一個類中:
14 /**
15  * Validate and prepare the given method override.
16  * Checks for existence of a method with the specified name,
17  * marking it as not overloaded if none found.
18  * @param mo the MethodOverride object to validate
19  * @throws BeanDefinitionValidationException in case of validation failure
20  */
21 protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
22     // 獲取對應類中對應方法名的個數
23     int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
24     if (count == 0) {
25         throw new BeanDefinitionValidationException(
26                 "Invalid method override: no method with name '" + mo.getMethodName() +
27                 "' on class [" + getBeanClassName() + "]");
28     }
29     else if (count == 1) {
30         // Mark override as not overloaded, to avoid the overhead of arg type checking.
31         // 標記MethodOverride暫未被覆蓋,避免參數類型的檢查的開銷
32         mo.setOverloaded(false);
33     }
34 }

spring是存在lookup-method和replace-method的,而這兩個配置的加載其實就是將配置統一存放到BeanDefinition中的methodOverride屬性里,
這兩個方法的實現原理是在bean實例化的時候檢測到存在MethodOverride,會動態的為當前bean生成動態代理並使用對應的攔截器為bean做增強處理,
相關邏輯實現在bean的實例化部分詳細及講解
但是,對於方法的匹配來講,如果一個類中存在若干個重載方法,那么,在函數調用及增強的時候,還需要根據參數類型進行匹配,來最終確認當前調用的是
哪個函數。但是,spring將一部分匹配工作在這里完成了,如果當前類中的方法只有一個,那么就設置重載方法沒有重載,這樣在后續調用的時候便可以直接
使用找到的方法,而不需要進行方法的參數匹配驗證了,而且還可以提前對方法存在性進行驗證。

5.2 實例化的前置處理
在真正調用doCreat方法創建bean之前調用了一個代理的方法,resolveBeforeInstantiation(beanName, mbdToUse),對BeanDefinition中屬性做了前置處理,
當然,無論其中是否有邏輯實現,我們都可以理解,因為真正的邏輯實現前后留有處理函數,也是可擴展的一種體現,但是,這並不是最重要的,在函數中
還提供了一個短路判斷,這才是最關鍵的部分(TODO:這里不是很懂,為什么這個短路操作最關鍵!!!)
if (bean != null) {
  return bean;
}
當前置處理返回的結果如果不為空,那么直接略過后續的bean的創建而直接返回結果,這一特性雖然很容易被忽略,但是起着至關重要的作用,我們熟悉的AOP功能
就是在這里判斷的

org.springframework.beans.factory.support包下AbstractAutowireCapableBeanFactory類中resolveBeforeInstantiation方法

 1 /**
 2  * Apply before-instantiation post-processors, resolving whether there is a
 3  * before-instantiation shortcut for the specified bean.
 4  * @param beanName the name of the bean
 5  * @param mbd the bean definition for the bean
 6  * @return the shortcut-determined bean instance, or {@code null} if none
 7  */
 8 @Nullable
 9 protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
10     Object bean = null;
11     // 如果尚未被解析
12     if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
13         // Make sure bean class is actually resolved at this point.
14         if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
15             Class<?> targetType = determineTargetType(beanName, mbd);
16             if (targetType != null) {
17                 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
18                 if (bean != null) {
19                     bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
20                 }
21             }
22         }
23         mbd.beforeInstantiationResolved = (bean != null);
24     }
25     return bean;
26 }

此方法中最吸引人的方法是applyBeanPostProcessorsBeforeInstantiation以及applyBeanPostProcessorsAfterInitialization方法,兩個方法的實現非常簡單,
無非是對后處理器中的所有InstantiationAwareBeanPostProcessor類型的后處理器進行postProcessBeforeInstantiation方法和BeanPostProcessor類型的
postProcessAfterInitialization方法的調用

(1)實例化前的后處理應用
bean的實例化前調用,也就是將AbstractBeanDefinition轉換為BeanWrapper前處理,給子類一個修改BeanDefinition的機會,也就是說,bean通過這個方法處理之后
可能不是我們之前的bean了

 1 @Nullable
 2 protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
 3     for (BeanPostProcessor bp : getBeanPostProcessors()) {
 4         if (bp instanceof InstantiationAwareBeanPostProcessor) {
 5             InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
 6             Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
 7             if (result != null) {
 8                 return result;
 9             }
10         }
11     }
12     return null;
13 }

(2)實例化后的后處理應用
在講解從緩存中獲取單例bean的時候提過,spring中的規則是在bean的初始化后盡可能保證將注冊的后處理器postProcessAfterInitialization方法應用到bean中,
因為如果返回的bean不為空,那么便不會再次經歷普通bean的創建過程,所以只能在這里應用后處理器的postProcessAfterInitialization方法

 1 在講解從緩存中獲取單例bean的時候提過,spring中的規則是在bean的初始化后盡可能保證將注冊的后處理器postProcessAfterInitialization方法應用到bean中,
 2 因為如果返回的bean不為空,那么便不會再次經歷普通bean的創建過程,所以只能在這里應用后處理器的postProcessAfterInitialization方法
 3 @Override
 4 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
 5         throws BeansException {
 6 
 7     Object result = existingBean;
 8     for (BeanPostProcessor processor : getBeanPostProcessors()) {
 9         Object current = processor.postProcessAfterInitialization(result, beanName);
10         if (current == null) {
11             return result;
12         }
13         result = current;
14     }
15     return result;
16 }

6、循環依賴

6.1什么是循環依賴
循環依賴就是循環引用,就是兩個或者多個bean 相互之間的持有對方,比如:CircleA調用了CircleB,CircleB引用了CircleC,CircleC引用了CircleA,則
他們最終反應成一個環,此處不是循環調用,循環調用是方法之前的調用

6.2spring如何解決循環依賴
spring容器循環依賴包括構造器循環依賴和setter循環依賴,首先來定義一下循環引用類:

 1 public class TestA{
 2 
 3     private TestB testB;
 4     
 5     public void a(){
 6         testB.b();
 7     }
 8     
 9     public void setTestB(TestB testB){
10         this.testB = testB;
11     }
12     
13     public TestB getTestB(){
14         return testB;
15     }
16 }
17 
18 public class TestB{
19 
20     private TestC testC;
21     
22     public void b(){
23         testC.c();
24     }
25     
26     public void setTestC(TestC testC){
27         this.testC = testC;
28     }
29     
30     public TestC getTestC(){
31         return testC;
32     }
33 }
34 
35 public class TestC{
36 
37     private TestA testA;
38     
39     public void c(){
40         testA.a();
41     }
42     
43     public void setTestA(TestA testA){
44         this.testA = testA;
45     }
46     
47     public TestA getTestA(){
48         return testA;
49     }
50 }

spring 中將循環依賴的處理分成了三種情況:
(1)構造器循環依賴
表示通過構造器注入構成的循環依賴,次依賴是無法解決的,只能拋出異常BeanCurrentlyInCreationException異常表示循環依賴
如在創建TestA類時,構造器需要TestB,在創建TestB 時又發現需要TestC,則又去創建TestC,最終在創建TestC時發現又需要TestA,從而形成一個環,沒法創建

spring容器將每一個正在創建的bean標識符放在一個“當前創建bean池”,bean標識符在創建過程中將一直保持在這個池中,因此如果在創建過程中發現自己已經在
“當前創建bean池”中,將拋出BeanCurrentlyInCreationException異常表示循環依賴;而對於創建完畢的bean將從“當前創建bean池”中清除掉
看一段配置文件,來分析一下其中的,在spring中的創建過程 這其實就是上面代碼在xml中的翻譯

<bean id="testA" class="com.bean.TestA">
  <constructor-arg index="0" ref="testB" />
</bean>
<bean id="testB" class="com.bean.TestB">
  <constructor-arg index="0" ref="testC" />
</bean>
<bean id="testC" class="com.bean.testC">
  <constructor-arg index="0" ref="testA" />
</bean>

解析:
spring容器創建“testA”bean,首先去“當前創建bean池”查找是否當前bean正在創建,如果沒發現,則繼續准備其需要的構造器參數”testB“,並將”testA“
標識符當到“當前創建bean池”
spring容器創建“testB”bean,首先去“當前創建bean池”查找是否當前bean正在創建,如果沒發現,則繼續准備其需要的構造器參數”testC“,並將”testB“
標識符當到“當前創建bean池”
spring容器創建“testC”bean,首先去“當前創建bean池”查找是否當前bean正在創建,如果沒發現,則繼續准備其需要的構造器參數”testA“,並將”testC“
標識符當到“當前創建bean池”,但是當去創建testA時,發現該bean標識符在“當前創建bean池”中,因為表示循環依賴,拋出BeanCurrentlyInCreationException

(2)setter循環依賴
表示通過setter注入的方式形成的循環依賴,對於setter注入造成的依賴是通過spring容器提前暴露剛完成的構造器注入但未完成其他步驟(setter注入)的
bean來完成的,而且只能解決單例作用域的bean循環依賴。通過提前暴露一個單例工廠方法,從而使得其他bean能引用到該bean,如下代碼:

1 addSingletonFactory(beanName, new ObjectFactory(){
2     public Object getObject(){
3         return getEarlyBeanRefrence(beanName,mbd,bean);
4     }
5 });

具體步驟分析:
spring容器創建“testA”bean,首先根據無參構造器創建bean,並暴露一個“ObjectFactory”,用於返回一個提前暴露一個創建中的bean,並將“testA”標識符
當到“當前創建bean池”,然后進行setter注入“testB”

spring容器創建“testB”bean,首先根據無參構造器創建bean,並暴露一個“ObjectFactory”,用於返回一個提前暴露一個創建中的bean,並將“testB”標識符
當到“當前創建bean池”,然后進行setter注入“circle”

spring容器創建“testC”bean,首先根據無參構造器創建bean,並暴露一個“ObjectFactory”,用於返回一個提前暴露一個創建中的bean,並將“testC”標識符
當到“當前創建bean池”,然后進行setter注入“testA”,進行注入“testA”時由於提前暴露了“ObjectFactory”工廠,從而使它返回提前暴露一個創建中的bean

最后在依賴注入“testA”和“testB”,完成依賴注入

(3)protoType范圍的依賴處理
對於“protoType”作用域bean,spring容器無法完成依賴注入,因為spring容器不進行緩存“protoType”作用域的bean,因此無法暴露一個創建中的bean
對於“singleston”作用域的bean,可以通過“setAllowCircularReferences(false)”來禁用循環引用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM