本篇文章主要介紹 Spring IoC 容器 getBean()
方法。java
下圖是一個大體的流程圖:git
首先定義一個簡單的 POJO,以下:github
public class User { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
再編寫一個 XML 文件。spring
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="com.leisurexi.ioc.domain.User"> <property name="id" value="1"/> <property name="name" value="leisurexi"/> </bean> </beans>
最後再來一個測試類。緩存
@Test public void test(){ DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions("META-INF/spring-bean.xml"); User user = beanFactory.getBean("user", User.class); System.out.println(user); }
上面的代碼仍是上篇文章的示例代碼,此次咱們主要分析 beanFactory.getBean()
方法。app
/** * @param name bean的名稱 * @param requiredType 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; // Eagerly check singleton cache for manually registered singletons. // 直接嘗試從緩存獲取或 singletonFactories 中的 ObjectFactory 中獲取,見下文詳解 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } // 檢查bean是不是FactoryBean的實現。不是直接返回bean,是的話首先檢查beanName是否以 & 開頭 // 若是是返回FactoryBean自己,不是調用FactoryBean#getObject()返回對象 // 見下文詳解 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. // 只有在單例狀況下才會去嘗試解決循環依賴,原型模式下,若是存在A中有 // B屬性,B中有A屬性,那麼當依賴注入時,就會產生當A還未建立完的時候 // 對於B的建立而在此返回建立A,形成循環依賴 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. // 檢查當前bean的BeanDefinition是否在當前的beanFactory,不在遞歸調用父工廠的getBean()去獲取bean BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { // No args -> delegate to standard getBean method. 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); // Guarantee initialization of beans that the current bean depends on. // 實例化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); } } } // Create bean instance. // 若是 bean 的做用域是單例 if (mbd.isSingleton()) { // 建立和註冊單例 bean,見下文詳解 sharedInstance = getSingleton(beanName, () -> { try { // 建立 bean 實例,下篇文章詳解 return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); // 上文解釋過,這裏再也不贅述 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // bean 的做用域是原型 else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { // 原型 bean 建立前回調,默認實現是將 beanName 保存到 prototypesCurrentlyInCreation 緩存中 beforePrototypeCreation(beanName); // 建立 bean 實例,下篇文章詳解 prototypeInstance = createBean(beanName, mbd, args); } finally { // 原型 bean 建立後回調,默認實現是將 beanName 從prototypesCurrentlyInCreation 緩存中移除 afterPrototypeCreation(beanName); } // 上文解釋過,這裏再也不贅述 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 建立前回調,默認實現是將 beanName 保存到 prototypesCurrentlyInCreation 緩存中 beforePrototypeCreation(beanName); try { // 建立 bean 實例,下篇文章詳解 return createBean(beanName, mbd, args); } finally { // 原型 bean 建立後回調,默認實現是將 beanName 從 prototypesCurrentlyInCreation 緩存中移除 afterPrototypeCreation(beanName); } }); // 上文解釋過,這裏再也不贅述 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; } } // Check if required type matches the type of the actual bean instance. // 檢查所需的類型是否與實際 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) { if (logger.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } // 返回 bean 實例 return (T) 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; // Handle aliasing... String resolvedName; // 若是name是別名,則會循環去查找bean的實際名稱 do { resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); return canonicalName; }
上面代碼首先去除 FactoryBean
的修飾符,好比 name=&aa
,那麼會首先去除 &
使 name=aa
。而後取 alias
所表示的最終 beanName
。框架
咱們這裏簡單介紹什麼是 FactoryBean
。less
通常狀況下,Spring 經過反射機制利用 bean
的 class
屬性指定實現類來實例化 bean
。在某些狀況下,實例化 bean
過程比較複雜,若是按照傳統的方式,則須要在 <bean>
中提供大量的配置信息,配置方式的靈活性是受限的,這是採用編碼的方式可能會獲得一個簡單的方案。Spring 爲此提供了 org.springframework.bean.factory.FactoryBean
的工廠類接口,用戶能夠經過實現該接口定製實例化 bean
的邏輯。dom
FactoryBean
接口對於 Spring 框架來講佔有重要的地位,Spring 自身就提供了70多個 FactoryBean
的實現。它們隱藏了一下複雜 bean
的細節,給上層應用帶來了便利。下面是該接口的定義:ide
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
實體類:
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
的全部屬性配置值。
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 中配置。
<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/spring-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()
返回的對象。
public Object getSingleton(String beanName) { // allowEarlyReference設置爲true表示容許早期依賴 return getSingleton(beanName, true); } /** * @param allowEarlyReference 是否提早建立曝光 */ protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 檢查單例傳中是否存在 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 若是爲空,鎖定全局變量進行處理 synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 當某些方法須要提早初始化時則會調用addSingletonFactory方法將對應的 // ObjectFactory 初始化策略存儲在 singletonFactories ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 調用預先設定的getObject() singletonObject = singletonFactory.getObject(); // 記錄在緩存中,earlySingletonObjects和singletonFactories this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
上面代碼涉及到循環依賴的檢測,首先嚐試從 singletonObjects
裏面獲取實例,若是獲取不到再從 earlySingletonObjects
裏面獲取,若是還獲取不到,再嘗試從 singletonFactories
裏面獲取 beanName
對應的 ObjectFactory
,而後調用這個 ObjectFactory
的 getObject()
來建立 bean
,並放到 earlySingletonObjects
裏面去,而且從 singletonFactories
裏面 remove
掉這個 ObjectFactory
,而對於後續的全部內存操做都只爲了循環依賴檢測時候用,也就是在 allowEarlyReference
爲 true
的狀況下才會使用。
這裏涉及用於存儲 bean
不一樣的 map
,下面簡單解釋下:
beanName
和 bean
實例之間的關係。beanName
和建立 bean
的工廠之間的關係。beanName
和 bean
實例之間的關係,與 singletonObjects
的不一樣之處在於,當一個單例 bean
被放到這裏後,那麼當 bean
還在建立過程當中,就能夠經過 getBean()
獲取到了,其目的是用來檢測循環引用。bean
。protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // Don't let calling code try to dereference the factory if the bean isn't a factory. // 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; } // Now we have the bean instance, which may be a normal bean or a FactoryBean. // If it's a FactoryBean, we use it to create a bean instance, unless the // caller actually wants a reference to the factory. // name 不是 & 開頭,而且不是 FactoryBean 類型,直接返回 if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { // 從緩存中獲取實例 object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // Return bean instance from factory. // 將 beanInstance 強轉成 FactoryBean FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // Caches object obtained from FactoryBean if it is a singleton. // 合併 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); // Only post-process and store if not put there already during getObject() call above // (e.g. because of circular reference processing triggered by custom getBean calls) Object alreadyThere = this.factoryBeanObjectCache.get(beanName); // 若是該 beanName 已經在緩存中存在,則將 object 替換成緩存中的 if (alreadyThere != null) { object = alreadyThere; } else { if (shouldPostProcess) { // 若是當前 bean 還在建立中,直接返回 if (isSingletonCurrentlyInCreation(beanName)) { // Temporarily return non-post-processed object, not storing it yet. 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 { if (System.getSecurityManager() != null) { AccessControlContext acc = getAccessControlContext(); try { object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 調用 getObject() 獲取實例 object = factory.getObject(); } } catch (FactoryBeanNotInitializedException ex) { throw new BeanCurrentlyInCreationException(beanName, ex.toString()); } catch (Throwable ex) { throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex); } // Do not accept a null value for a FactoryBean that's not fully // initialized yet: Many FactoryBeans just return null then. // 若是 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 { // Quick check on the concurrent map first, with minimal locking. // 獲取當前bean合併後的BeanDefinition RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); // 若是存在合併後的BeanDefinition,而且不是過時的,直接返回 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; // Check with full lock now in order to enforce the same merged instance. // 若是bean是頂級bean,直接獲取合併後的BeanDefinition if (containingBd == null) { mbd = this.mergedBeanDefinitions.get(beanName); } // 沒有合併後的BeanDefinition || BeanDefinition過時了 if (mbd == null || mbd.stale) { previous = mbd; // 若是bean沒有parent if (bd.getParentName() == null) { // Use copy of given root bean definition. // 若是bd自己就是RootBeanDefinition直接複製一份,不然建立一個 if (bd instanceof RootBeanDefinition) { mbd = ((RootBeanDefinition) bd).cloneBeanDefinition(); } else { mbd = new RootBeanDefinition(bd); } } else { // Child bean definition: needs to be merged with parent. // bean有parent BeanDefinition pbd; try { // 獲取parent bean的實際名稱 String parentBeanName = transformedBeanName(bd.getParentName()); if (!beanName.equals(parentBeanName)) { // 當前beanName不等於它的parent beanName // 獲取parent合併後的BeanDefinition pbd = getMergedBeanDefinition(parentBeanName); } else { // 若是父定義的beanName與bd的beanName相同,則拿到父BeanFactory // 只有在存在父BeanFactory的狀況下,才容許父定義beanName與本身相同 BeanFactory parent = getParentBeanFactory(); if (parent instanceof ConfigurableBeanFactory) { // 若是父BeanFactory是ConfigurableBeanFactory // 則經過父BeanFactory獲取parent合併後的BeanDefinition 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); } // Deep copy with overridden values. // 使用父定義pbd構建一個新的RootBeanDefinition對象(深拷貝) mbd = new RootBeanDefinition(pbd); // 覆蓋與parent相同的屬性, mbd.overrideFrom(bd); } // Set default singleton scope, if not configured before. // 若是bean沒有設置scope屬性,默認是singleton if (!StringUtils.hasLength(mbd.getScope())) { mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON); } // A bean contained in a non-singleton bean cannot be a singleton itself. // Let's correct this on the fly here, since this might be the result of // parent-child merging for the outer bean, in which case the original inner bean // definition will not have inherited the merged outer bean's singleton status. // 當前bean是嵌套bean && 頂級bean的做用域不是單例 && 當前bean的做用域是單例 // 這裏總結起來就是,若是頂層bean不是單例的,那麼嵌套bean也不能是單例的 if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) { // 設置當前bean的做用域和頂級bean同樣 mbd.setScope(containingBd.getScope()); } // Cache the merged bean definition for the time being // (it might still get re-merged later on in order to pick up metadata changes) // 當前bean是頂級bean && 緩存bean的元數據(該值默認爲true) if (containingBd == null && isCacheBeanMetadata()) { // 將當前bean合併後的RootBeanDefinition緩存起來 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; } // 解析別名 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; }
這裏的 dependentBeanMap
實際上是 beanName
和其依賴的 dependentBeanName
反過來存的。好比,A 依賴 B,B 依賴 A;那麼首先調用 getBean()
獲取 A,而後到 isDependent()
,由於是第一次進來因此 dependentBeans
是空的直接返回 false
,接着到下面 registerDepenndentBean()
,這裏先將 dependentBeanName
做爲 key
,value
是添加了 beanName
的 LinkedHashSet
,添加進 dependentBeanMap
;而後由於依賴 B,因此去實例化 B,又因爲 B 依賴 A,到了 isDepnedent()
,接着 dependentBeans.contains(dependentBeanName)
這行代碼會返回 true
(由於在實例化 A 的過程當中,已經將 B 做爲 key
放入了 dependentBeanMap
),最後直接拋出 循環引用 的異常。
public void registerDependentBean(String beanName, String dependentBeanName) { // 解析別名 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); } }
這個方法又引入了一個跟 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!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } // 建立單例 bean 以前的回調 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 獲取 bean 實例,在此處纔會去真正調用建立 bean 的方法,也就是 createBean 方法 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } 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); // 移除 bean 的工廠 this.singletonFactories.remove(beanName); // bean 已經實際建立完畢,這裏從早起單例緩存中刪除 this.earlySingletonObjects.remove(beanName); // 將 beanName 添加到已註冊 bean 緩存中 this.registeredSingletons.add(beanName); } }
上面方法是單例 bean
的處理邏輯,主要作的就是建立 bean
實例,而後將實例放入到緩存中;而後下次再獲取該 bean
是直接從緩存中獲取返回。
在建立 bean
實例的先後提供了兩個擴展點,分別是 beforeSingletonCreation()
和 afterSingletonCreation()
,咱們能夠繼承 DefaultSingletonBeanRegistry
來擴展這兩個方法。
咱們實現一個 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/spring-bean.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
實例的類型匹配,若是不等進行轉換,最後返回實例。最後,我模仿 Spring 寫了一個精簡版,代碼會持續更新,如今是 0.0.1
版本。地址:https://github.com/leisurexi/tiny-spring。訪問新博客地址,觀看效果更佳 https://leisurexi.github.io/