本系列所有基於 Spring 5.2.2.BUILD-SNAPSHOT
版本。由於 Spring 整個體系太過於龐大,因此只會進行關鍵部分的源碼解析。html
本篇文章主要介紹 Spring IoC 容器是怎麼加載 bean
的。java
咱們先看一下Spring IoC BeanDefinition 的加載和註冊一文中獲取 bean
的實例代碼:git
public class BeanDefinitionDemo { public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions("META-INF/bean-definition.xml"); User user = beanFactory.getBean("user", User.class); System.err.println(user); } }
經過 beanFactory.getBean()
這個方法就獲取了在 XML 中定義的 bean
,下面咱們就重點分析這個方法背後作了什麼操做。github
在正式開始以前,咱們先了解一下 FactoryBean
及其用法。spring
FactoryBean
接口對於 Spring 框架來講佔有重要的地位,Spring 自身就提供了70多個 FactoryBean
的實現。它們隱藏了一下複雜 bean
的細節,給上層應用帶來了便利。下面是該接口的定義:緩存
public interface FactoryBean<T> { // 返回由FactoryBean建立的bean實例,若是isSingleton()返回true, // 則該實例會放到Spring容器中單例緩存池中 @Nullable T getObject() throws Exception; // 返回FactoryBean建立的bean類型 @Nullable Class<?> getObjectType(); // 返回由FactoryBean建立的bean實例的做用域是singleton仍是prototype default boolean isSingleton() { return true; } }
當配置文件中 <bean>
的 class
屬性配置的實現類時 FactoryBean
時,經過 getBean()
返回的不是 FactoryBean
自己,而是 FactoryBean#getObject()
所返回的對象,至關於 FactoryBean#getObject()
代理了 getBean()
。下面用簡單的代碼演示一下:框架
首先定義一個 Car
實體類:less
public class Car { private Integer maxSpeed; private String brand; private Double price; public Integer getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(Integer maxSpeed) { this.maxSpeed = maxSpeed; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } }
上面的實體類,若是用傳統方式配置,每個屬性都會對應一個 <property>
元素標籤。若是用 FactoryBean
的方式實現就會靈活一點,下面經過逗號分隔的方式一次性的爲 Car
的全部屬性配置值。dom
public class CarFactoryBean implements FactoryBean<Car> { private String carInfo; @Override public Car getObject() throws Exception { Car car = new Car(); String[] infos = carInfo.split(","); car.setBrand(infos[0]); car.setMaxSpeed(Integer.valueOf(infos[1])); car.setPrice(Double.valueOf(infos[2])); return car; } @Override public Class<?> getObjectType() { return Car.class; } @Override public boolean isSingleton() { return true; } public String getCarInfo() { return carInfo; } public void setCarInfo(String carInfo) { this.carInfo = carInfo; } }
接下來,咱們在 XML 中配置。ide
<bean id="car" class="com.leisurexi.ioc.domain.CarFactoryBean"> <property name="carInfo" value="超級跑車,400,2000000"/> </bean>
最後看下測試代碼和運行結果:
@Test public void factoryBeanTest() { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions("META-INF/factory-bean.xml"); Car car = beanFactory.getBean("car", Car.class); System.out.println(car); CarFactoryBean carFactoryBean = beanFactory.getBean("&car", CarFactoryBean.class); System.out.println(carFactoryBean); }
能夠看到若是 beanName
前面加上 &
獲取的是 FactoryBean
自己,不加獲取的 getObject()
返回的對象。
FactoryBean
的特殊之處在於它能夠向容器中註冊兩個bean
,一個是它自己,一個是FactoryBean.getObject()
方法返回值所表明的bean
。
public <T> T getBean(String name, Class<T> requiredType) throws BeansException { // 調用doGetBean方法(方法以do開頭實際作操做的方法) return doGetBean(name, requiredType, null, false); } /** * @param name bean的名稱 * @param requiredType bean的類型 * @param args 顯示傳入的構造參數 * @param typeCheckOnly 是否僅僅作類型檢查 */ protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 獲取bean的實際名稱,見下文詳解 final String beanName = transformedBeanName(name); Object bean; // 直接嘗試從緩存獲取或 singletonFactories 中的 ObjectFactory 中獲取,見下文詳解 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // 檢查bean是不是FactoryBean的實現。不是直接返回bean, // 是的話首先檢查beanName是否以&開頭,若是是返回FactoryBean自己, // 不是調用FactoryBean#getObject()返回對象,見下文詳解 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // 只有在單例狀況下才會去嘗試解決循環依賴,原型模式下,若是存在A中有 // B屬性,B中有A屬性,那麼當依賴注入時,就會產生當A還未建立完的時候 // 對於B的建立而在此返回建立A,形成循環依賴 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 檢查當前bean的BeanDefinition是否在當前的bean工廠中, // 不在遞歸調用父工廠的getBean()去獲取bean BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } // 若是不是僅僅作類型檢查,則是建立bean,這裏要進行記錄 if (!typeCheckOnly) { // 記錄bean已經建立過 markBeanAsCreated(beanName); } try { // 合併BeanDefinition,見下文詳解 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // 實例化bean前先實例化依賴bean,也就是depends-on屬性中配置的beanName String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { // 檢查是否循環依賴,即當前bean依賴dep,dep依賴當前bean,見下文詳解 if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // 將dep和beanName的依賴關係放入到緩存中,見下文詳解 registerDependentBean(dep, beanName); try { // 獲取依賴dep對應的bean實例,若是還未建立實例,則先去建立 getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 若是 bean 的做用域是單例 if (mbd.isSingleton()) { // 建立和註冊單例 bean,見下文詳解 sharedInstance = getSingleton(beanName, () -> { try { // 建立 bean 實例 return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); // 獲取bean實例 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // bean 的做用域是原型 else if (mbd.isPrototype()) { Object prototypeInstance = null; try { // 原型 bean 建立前回調, // 默認實現是將 beanName 保存到 prototypesCurrentlyInCreation 緩存中 beforePrototypeCreation(beanName); // 建立 bean 實例 prototypeInstance = createBean(beanName, mbd, args); } finally { // 原型 bean 建立後回調, // 默認實現是將 beanName 從prototypesCurrentlyInCreation 緩存中移除 afterPrototypeCreation(beanName); } // 獲取bean實例 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } // 自定義做用域 else { // 獲取自定義做用域名稱 String scopeName = mbd.getScope(); // 獲取做用域對象 final Scope scope = this.scopes.get(scopeName); // 若是爲空表示做用域未註冊,拋出異常 if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { // 其餘 Scope 的 bean 建立 // 新建了一個 ObjectFactory,而且重寫了 getObject 方法 Object scopedInstance = scope.get(beanName, () -> { // 調用原型 bean 建立前回調 beforePrototypeCreation(beanName); try { // 建立 bean 實例,下篇文章詳解 return createBean(beanName, mbd, args); } finally { // 調用原型 bean 建立後回調 afterPrototypeCreation(beanName); } }); // 獲取bean實例 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // 檢查所需的類型是否與實際 bean 實例的類型匹配 if (requiredType != null && !requiredType.isInstance(bean)) { try { // 若是類型不等,進行轉換,轉換失敗拋出異常;轉換成功直接返回 T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } // 返回 bean 實例 return (T) bean; }
上面方法就是獲取 bean
的整個流程,下面咱們對其調用的其它主要方法來一一分析。
protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } // BeanFactoryUtils.java public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); // 若是name不是&開頭,直接返回 if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { return name; } // 去除name的&前綴 return transformedBeanNameCache.computeIfAbsent(name, beanName -> { do { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); return beanName; }); } // SimpleAliasRegistry.java public String canonicalName(String name) { String canonicalName = name; String resolvedName; // 若是name是別名,則會循環去查找bean的實際名稱 do { resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); return canonicalName; }
public Object getSingleton(String beanName) { // allowEarlyReference設置爲true表示容許早期依賴 return getSingleton(beanName, true); } protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 先從一級緩存中,檢查單例緩存是否存在 Object singletonObject = this.singletonObjects.get(beanName); // 若是爲空,而且當前bean正在建立中,鎖定全局變量進行處理 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 從二級緩存中獲取 singletonObject = this.earlySingletonObjects.get(beanName); // 二級緩存爲空 && bean容許提早曝光 if (singletonObject == null && allowEarlyReference) { // 從三級緩存中獲取bean對應的ObjectFactory ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 調用預先設定的getObject(),獲取bean實例 singletonObject = singletonFactory.getObject(); // 放入到二級緩存中,並從三級緩存中刪除 // 這時bean已經實例化完但還未初始化完 // 在該bean未初始化完時若是有別的bean引用該bean,能夠直接從二級緩存中取出返回 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
上面方法主要就是嘗試從緩存中獲取 bean
,緩存有三級,這也是 Spring 解決循環依賴的關鍵所在;後續會在 循環依賴 中重點講述。
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // name 是否以 & 開頭 if (BeanFactoryUtils.isFactoryDereference(name)) { // 若是是 null 直接返回 if (beanInstance instanceof NullBean) { return beanInstance; } // beanName 以 & 開頭,但又不是 FactoryBean 類型,拋出異常 if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); } // 設置 isFactoryBean 爲 true if (mbd != null) { mbd.isFactoryBean = true; } // 返回 bean 實例 return beanInstance; } // name 不是 & 開頭,而且不是 FactoryBean 類型,直接返回 if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } // 到這裏就表明name不是&開頭,且是FactoryBean類型 // 即獲取FactoryBean.getObject()方法返回值所表明的bean Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { // 從緩存中獲取實例 object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // 將 beanInstance 強轉成 FactoryBean FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // 合併 BeanDefinition if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); // 獲取實例 object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } // FactoryBeanRegistrySupport.java protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { // 若是是單例 bean,而且已經存在緩存中 if (factory.isSingleton() && containsSingleton(beanName)) { // 加鎖 synchronized (getSingletonMutex()) { // 從緩存中獲取 Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { // 調用 FactoryBean 的 getObject() 獲取實例 object = doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this.factoryBeanObjectCache.get(beanName); // 若是該 beanName 已經在緩存中存在,則將 object 替換成緩存中的 if (alreadyThere != null) { object = alreadyThere; } else { if (shouldPostProcess) { // 若是當前 bean 還在建立中,直接返回 if (isSingletonCurrentlyInCreation(beanName)) { return object; } // 單例 bean 建立前回調 beforeSingletonCreation(beanName); try { // 對從 FactoryBean 得到給定對象的後置處理,默認按原樣返回 object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } finally { // 單例 bean 建立後回調 afterSingletonCreation(beanName); } } if (containsSingleton(beanName)) { // 將 beanName 和 object 放到 factoryBeanObjectCache 緩存中 this.factoryBeanObjectCache.put(beanName, object); } } } // 返回實例 return object; } } else { // 調用 FactoryBean 的 getObject() 獲取實例 Object object = doGetObjectFromFactoryBean(factory, beanName); if (shouldPostProcess) { try { // 對從 FactoryBean 得到給定對象的後置處理,默認按原樣返回 object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); } } // 返回實例 return object; } } // FactoryBeanRegistrySupport.java private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) throws BeanCreationException { Object object; try { // 調用 getObject() 獲取實例 object = factory.getObject(); } // 省略異常處理... // 若是 object 爲 null,而且當前 singleton bean 正在建立中,拋出異常 if (object == null) { if (isSingletonCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject"); } object = new NullBean(); } // 返回 object 實例 return object; }
上面代碼總結起來就是:若是 beanName
以 &
開頭,直接返回 FactoryBean
實例;不然調用 getObject()
方法獲取實例,而後執行 postProcessObjectFromFactoryBean()
回調,能夠在回調方法中修改實例,默認按原樣返回。
下文將合併後的
BeanDefinition
簡稱爲MergedBeanDefinition
。
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException { // 從緩存獲取MergedBeanDefinition RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); // 若是存在MergedBeanDefinition,而且不是過時的,直接返回 if (mbd != null && !mbd.stale) { return mbd; } // 獲取已經註冊的BeanDefinition而後去合併 return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); } protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) throws BeanDefinitionStoreException { // 頂級bean獲取合併後的BeanDefinition return getMergedBeanDefinition(beanName, bd, null); } /** * @param containingBd 若是是嵌套bean該值爲頂級bean,若是是頂級bean該值爲null */ protected RootBeanDefinition getMergedBeanDefinition( String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException { // 加鎖 synchronized (this.mergedBeanDefinitions) { // 本次的RootBeanDefinition RootBeanDefinition mbd = null; // 之前的RootBeanDefinition RootBeanDefinition previous = null; // 若是bean是頂級bean,直接獲取MergedBeanDefinition if (containingBd == null) { mbd = this.mergedBeanDefinitions.get(beanName); } // 沒有MergedBeanDefinition || BeanDefinition過時了 if (mbd == null || mbd.stale) { previous = mbd; // 若是bean沒有parent if (bd.getParentName() == null) { // 若是bd自己就是RootBeanDefinition直接複製一份,不然建立一個 if (bd instanceof RootBeanDefinition) { mbd = ((RootBeanDefinition) bd).cloneBeanDefinition(); } else { mbd = new RootBeanDefinition(bd); } } else { // bean有parent BeanDefinition pbd; try { // 獲取parent bean的實際名稱 String parentBeanName = transformedBeanName(bd.getParentName()); if (!beanName.equals(parentBeanName)) { // 當前beanName不等於它的parentBeanName // 獲取parent的MergedBeanDefinition pbd = getMergedBeanDefinition(parentBeanName); } else { // 若是parentBeanName與bd的beanName相同,則拿到父BeanFactory // 只有在存在父BeanFactory的狀況下,才容許parentBeanName與本身相同 BeanFactory parent = getParentBeanFactory(); if (parent instanceof ConfigurableBeanFactory) { // 若是父BeanFactory是ConfigurableBeanFactory類型 // 則經過父BeanFactory獲取parent的MergedBeanDefinition pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName); } else { // 若是父BeanFactory不是ConfigurableBeanFactory,拋出異常 throw new NoSuchBeanDefinitionException(parentBeanName, "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName + "': cannot be resolved without an AbstractBeanFactory parent"); } } } catch (NoSuchBeanDefinitionException ex) { throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName, "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex); } // 使用父MergedBeanDefinition構建一個新的RootBeanDefinition對象(深拷貝) mbd = new RootBeanDefinition(pbd); // 覆蓋與parent相同的屬性 mbd.overrideFrom(bd); } // 若是bean沒有設置scope屬性,默認是singleton if (!StringUtils.hasLength(mbd.getScope())) { mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON); } // 當前bean是嵌套bean && 頂級bean的做用域不是單例 && 當前bean的做用域是單例 // 這裏總結起來就是,若是頂層bean不是單例的,那麼嵌套bean也不能是單例的 if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) { // 設置當前bean的做用域和頂級bean同樣 mbd.setScope(containingBd.getScope()); } // 當前bean是頂級bean && 緩存bean的元數據(該值默認爲true) if (containingBd == null && isCacheBeanMetadata()) { // 將當前bean的MergedBeanDefinition緩存起來 this.mergedBeanDefinitions.put(beanName, mbd); } } // 之前的RootBeanDefinition不爲空,拷貝相關的BeanDefinition緩存 if (previous != null) { copyRelevantMergedBeanDefinitionCaches(previous, mbd); } return mbd; } }
上面代碼主要是獲取 MergedBeanDefinition
,主要步驟以下:
首先從緩存中獲取 bean
的 MergedBeanDefinition
,若是存在而且未過時直接返回。
不存在或者已過時的 MergedBeanDefinition
,獲取已經註冊的 BeanDefinition
去做爲頂級 bean
合併。
bean
沒有 parent
(就是 XML 中的 parent 屬性),直接封裝成 RootBeanDefinition
。
bean
有 parent
,先去獲取父 MergedBeanDefinition
,而後覆蓋和合並與 parent
相同的屬性。
注意:這裏只有
abstract
、scope
、lazyInit
、autowireMode
、dependencyCheck
、dependsOn
、factoryBeanName
、factoryMethodName
、initMethodName
、destroyMethodName
會覆蓋,而constructorArgumentValues
、propertyValues
、methodOverrides
會合並。
若是沒有設置做用域,默認做用域爲 singleton
。
緩存 MergedBeanDefinition
。
上文中提到若是 bean
有 parent
,會合並一些屬性,這裏咱們稍微展現一下合併後的 propertyValues
:
首先定義一個 SuperUser
繼承上面定義的 User
,以下:
public class SuperUser extends User { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "SuperUser{" + "address='" + address + '\'' + '}'; } }
而後咱們在 XML 文件中配置一下,以下:
<bean id="superUser" class="com.leisurexi.ioc.domain.SuperUser" parent="user"> <property name="address" value="北京"/> </bean>
而後下圖是我 Debug 的截圖,能夠看到 superUser
的 propertyValues
合併了 user
的 id
和 name
屬性。
上文還提到了嵌套 bean
,下面咱們簡單看一下什麼是嵌套 bean
。
在 Spring 中,若是某個 bean
所依賴的 bean
不想被 Spring 容器直接訪問,可使用嵌套 bean
。和普通的 bean
同樣,使用 bean
元素來定義嵌套的 bean
,嵌套 bean
只對它的外部 bean
有效,Spring 沒法直接訪問嵌套 bean
,所以定義嵌套 bean
也無需指定 id
屬性。以下配置片斷是一個嵌套 bean
示例:
採用上面的配置形式能夠保證嵌套 bean
不能被容器訪問,所以不用擔憂其餘程序修改嵌套 bean
。外部 bean
的用法和使用結果和之前沒有區別。
嵌套
bean
提升了bean
的內聚性,可是下降了程序的靈活性。只有在肯定無需經過 Spring 容器訪問某個bean
實例時,才考慮使用嵌套bean
來定義。
protected boolean isDependent(String beanName, String dependentBeanName) { // 加鎖 synchronized (this.dependentBeanMap) { // 檢測beanName和dependentBeanName是否有循環依賴 return isDependent(beanName, dependentBeanName, null); } } private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) { // 若是當前bean已經檢測過,直接返回false if (alreadySeen != null && alreadySeen.contains(beanName)) { return false; } // 解析別名,獲取實際的beanName String canonicalName = canonicalName(beanName); // 獲取canonicalName所依賴beanName集合 Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName); // 若是爲空,二者還未肯定依賴關係,返回false if (dependentBeans == null) { return false; } // 若是dependentBeanName已經存在於緩存中,二者已經肯定依賴關係,返回true if (dependentBeans.contains(dependentBeanName)) { return true; } // 循環檢查,即檢查依賴canonicalName的全部beanName是否被dependentBeanName依賴(即隔層依賴) for (String transitiveDependency : dependentBeans) { if (alreadySeen == null) { alreadySeen = new HashSet<>(); } // 將已經檢查過的記錄下來,下次直接跳過 alreadySeen.add(beanName); if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) { return true; } } return false; }
public void registerDependentBean(String beanName, String dependentBeanName) { // 解析別名,獲取實際的beanName String canonicalName = canonicalName(beanName); // 加鎖 synchronized (this.dependentBeanMap) { // 獲取canonicalName依賴beanName集合,若是爲空默認建立一個LinkedHashSet當作默認值 Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); // 若是dependentBeanName已經記錄過了,直接返回 if (!dependentBeans.add(dependentBeanName)) { return; } } // 加鎖 synchronized (this.dependenciesForBeanMap) { // 這裏是和上面的dependentBeanMap倒過來,key爲dependentBeanName Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } }
下面咱們舉個A、B的 depends-on
屬性都是對方的例子:
首先獲取A,調用 isDependent()
方法,由於第一次獲取A,因此 dependentBeanMap
中沒有記錄依賴關係,直接返回 false
;接着調用registerDependentBean()
,這裏會向 dependentBeanMap
中反過來存儲依賴關係,也就是以B爲 key
,value
是一個包含A的 Set
集合。
接着會調用 getBean()
方法獲取B,首先調用 isDependent()
方法,由於在獲取A時已經存儲了B的依賴關係,因此獲取到的dependentBeans
的集合中包含A,因此直接返回true,拋出循環引用異常。
這個方法又引入了一個跟 dependentBeanMap
相似的緩存 dependenciesForBeanMap
。這兩個緩存很容易搞混,這裏再舉一個簡單的例子:A 依賴 B,那麼 dependentBeanMap
存放的是 key
爲 B,value
爲含有 A 的 Set
;而 dependenciesForBeanMap
存放的是key
爲 A,value
爲含有 B 的 Set
。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); // 加鎖 synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); // 緩存中不存在當前 bean,也就是當前 bean 第一次建立 if (singletonObject == null) { // 若是當前正在銷燬 singletons,拋出異常 if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } // 建立單例 bean 以前的回調 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 獲取 bean 實例,在此處纔會去真正調用建立 bean 的方法 singletonObject = singletonFactory.getObject(); newSingleton = true; } // 省略異常處理... finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } // 建立單例 bean 以後的回調 afterSingletonCreation(beanName); } if (newSingleton) { // 將 singletonObject 放入緩存 addSingleton(beanName, singletonObject); } } // 返回 bean 實例 return singletonObject; } } // 單例 bean 建立前的回調方法,默認實現是將 beanName 加入到當前正在建立 bean 的緩存中, // 這樣即可以對循環依賴進行檢測 protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } } // 單例 bean 建立後的回調方法,默認實現是將 beanName 從當前正在建立 bean 的緩存中移除 protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } } protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { // 這邊bean已經初始化完成了,放入一級緩存 this.singletonObjects.put(beanName, singletonObject); // 移除三級緩存 this.singletonFactories.remove(beanName); // 移除二級緩存 this.earlySingletonObjects.remove(beanName); // 將 beanName 添加到已註冊 bean 緩存中 this.registeredSingletons.add(beanName); } }
咱們實現一個 ThreadLocal
級別的做用域,也就是同一個線程內 bean
是同一個實例,不一樣線程的 bean
是不一樣實例。首先咱們繼承 Scope
接口實現,其中方法。以下:
public class ThreadLocalScope implements Scope { /** scope 名稱,在 XML 中的 scope 屬性就配置此名稱 */ public static final String SCOPE_NAME = "thread-local"; private final NamedThreadLocal<Map<String, Object>> threadLocal = new NamedThreadLocal<>("thread-local-scope"); /** * 返回實例對象,該方法被 Spring 調用 */ @Override public Object get(String name, ObjectFactory<?> objectFactory) { Map<String, Object> context = getContext(); Object object = context.get(name); if (object == null) { object = objectFactory.getObject(); context.put(name, object); } return object; } /** * 獲取上下文 map */ @NonNull private Map<String, Object> getContext() { Map<String, Object> map = threadLocal.get(); if (map == null) { map = new HashMap<>(); threadLocal.set(map); } return map; } @Override public Object remove(String name) { return getContext().remove(name); } @Override public void registerDestructionCallback(String name, Runnable callback) { // TODO } @Override public Object resolveContextualObject(String key) { Map<String, Object> context = getContext(); return context.get(key); } @Override public String getConversationId() { return String.valueOf(Thread.currentThread().getId()); } }
上面的 ThreadLocalScope
重點關注下 get()
便可,該方法是被 Spring 調用的。
而後在 XML 中配置 bean
的 scope
爲 thread-local
。以下:
<bean id="user" name="user" class="com.leisurexi.ioc.domain.User" scope="thread-local"> <property name="id" value="1"/> <property name="name" value="leisurexi"/> </bean>
接着咱們測試一下。測試類:
@Test public void test() throws InterruptedException { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 註冊自定義做用域 beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope()); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions("META-INF/custom-bean-scope.xml"); for (int i = 0; i < 3; i++) { Thread thread = new Thread(() -> { User user = beanFactory.getBean("user", User.class); System.err.printf("[Thread id :%d] user = %s%n", Thread.currentThread().getId(), user.getClass().getName() + "@" + Integer.toHexString(user.hashCode())); User user1 = beanFactory.getBean("user", User.class); System.err.printf("[Thread id :%d] user1 = %s%n", Thread.currentThread().getId(), user1.getClass().getName() + "@" + Integer.toHexString(user1.hashCode())); }); thread.start(); thread.join(); } }
說一下咱們這裏的主要思路,新建了三個線程,查詢線程內 user bean
是否相等,不一樣線程是否不等。
結果以下圖:
本文主要介紹了 getBean()
方法流程,咱們能夠從新梳理一下思路:
bean
實際名稱,若是緩存中存在直接取出實際 bean
返回。BeanDefinition
,沒有遞歸去父工廠建立 bean
。BeanDefinition
,若是 depends-on
不爲空,先去初始化依賴的 bean
。bean
的做用域是單例,調用 createBean()
方法建立實例,這個方法會執行 bean
的其它生命週期回調,以及屬性賦值等操做;接着執行單例 bean
建立先後的生命週期回調方法,並放入 singletonObjects
緩存起來。bean
的做用域是原型,調用 createBean()
方法建立實例,並執行原型 bean
先後調用生命週期回調方法。bean
的做用域是自定義的,獲取對應的 Scope
對象,調用重寫的 get()
方法獲取實例,並執行原型 bean
先後調用生命週期回調方法。bean
實例的類型匹配,若是不等進行轉換,最後返回實例。關於 createBean()
方法的細節,會在後續文章中進行分析。
最後,我模仿 Spring 寫了一個精簡版,代碼會持續更新。地址:https://github.com/leisurexi/tiny-spring。