對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)”來禁用循環引用