若是從單列緩存中沒有獲取到 Bean 對象,則說明有兩種狀況:java
針對這兩種狀況,Spring 是如何處理的呢?統一加載並完成初始化!這部份內容的篇幅較長,拆分爲兩部分:緩存
代碼以下:markdown
//AbstractBeanFactory.java // <3> 由於 Spring 只解決單例模式下得循環依賴,在原型模式下若是存在循環依賴則會拋出異常。 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // <4> 若是當前容器中沒有找到,則從父類容器中加載 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); // 若是,父類容器爲 AbstractBeanFactory ,直接遞歸查找 if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly); // 用明確的 args 從 parentBeanFactory 中,獲取 Bean 對象 } else if (args != null) { return (T)parentBeanFactory.getBean(nameToLookup, args); // 用明確的 requiredType 從 parentBeanFactory 中,獲取 Bean 對象 } else if (requiredType != null) { return parentBeanFactory.getBean(nameToLookup, requiredType); // 直接使用 nameToLookup 從 parentBeanFactory 獲取 Bean 對象 } else { return (T)parentBeanFactory.getBean(nameToLookup); } } // <5> 若是不是僅僅作類型檢查則是建立bean,這裏須要記錄 if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { // <6> 從容器中獲取 beanName 相應的 GenericBeanDefinition 對象,並將其轉換爲 RootBeanDefinition 對象 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 檢查給定的合併的 BeanDefinition checkMergedBeanDefinition(mbd, beanName, args); // <7> 處理所依賴的 bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { // 若給定的依賴 bean 已經註冊爲依賴給定的 bean // 即循環依賴的狀況,拋出 BeanCreationException 異常 if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // 緩存依賴調用 TODO 芋艿 registerDependentBean(dep, beanName); try { // 遞歸處理依賴 Bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // ... 省略不少代碼 }複製代碼
這段代碼主要處理如下幾個部分:ide
Spring 只解決單列模式下的循環依賴,對於原型模式的依賴則拋出 BeanCurrentlyInCreationException 異常post
//AbstractBeanFactory.java // 由於 Spring 只解決單例模式下得循環依賴,在原型模式下若是存在循環依賴則會拋出異常。 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } 複製代碼
調用 AbstractBeanFactory#isPrototypeCurrentlyInCreation(String beanName) 方法,判斷當前 Bean 是否正在建立。代碼以下:ui
//AbstractBeanFactory.java //ThreaadLocal 緩存建立的Bean private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<>("Prototype beans currently in creation"); protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName)|| (curVal instanceof Set && ((Set<?>)curVal).contains(beanName)))); }複製代碼
ThreadLocal 存儲的值在單列模式和原型模式是不同的
this
若是當前容器沒有找到 Bean ,就從父容器中加載。代碼以下:
spa
//AbstractBeanFactory.java // 獲取父容器 BeanFactory parentBeanFactory = getParentBeanFactory(); // 檢查父容器 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // 獲取原始 beanName String nameToLookup = originalBeanName(name); // 若是,父類容器爲 AbstractBeanFactory ,直接遞歸查找 if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly); // 用明確的 args 從 parentBeanFactory 中,獲取 Bean 對象 } else if (args != null) { return (T)parentBeanFactory.getBean(nameToLookup, args); // 用明確的 requiredType 從 parentBeanFactory 中,獲取 Bean 對象 } else if (requiredType != null) { return parentBeanFactory.getBean(nameToLookup, requiredType); // 直接使用 nameToLookup 從 parentBeanFactory 獲取 Bean 對象 } else { return (T)parentBeanFactory.getBean(nameToLookup); } }複製代碼
獲取父容器。代碼以下:prototype
//AbstractBeanFactory.java private BeanFactory parentBeanFactory; @Override public BeanFactory getParentBeanFactory() { return this.parentBeanFactory; }複製代碼
若父容器不爲空,而且 beanDefinitionMap 中沒有找到對應的 BeanDefinition 對象 。代碼以下:code
//DefaultListableBeanFactory.java private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); @Override public boolean containsBeanDefinition(String beanName) { Assert.notNull(beanName, "Bean name must not be null"); return this.beanDefinitionMap.containsKey(beanName); }複製代碼
獲取原始 beanName。代碼以下:
//AbstractBeanFactory.java protected String originalBeanName(String name) { String beanName = transformedBeanName(name); // <x> if (name.startsWith(FACTORY_BEAN_PREFIX)) { // <y> beanName = FACTORY_BEAN_PREFIX + beanName; } return beanName; }複製代碼
這裏都是委託父容器加載 Bean 的邏輯。代碼以下:
// 若是,父類容器爲 AbstractBeanFactory ,直接遞歸查找 if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly); // 用明確的 args 從 parentBeanFactory 中,獲取 Bean 對象 } else if (args != null) { return (T)parentBeanFactory.getBean(nameToLookup, args); // 用明確的 requiredType 從 parentBeanFactory 中,獲取 Bean 對象 } else if (requiredType != null) { return parentBeanFactory.getBean(nameToLookup, requiredType); // 直接使用 nameToLookup 從 parentBeanFactory 獲取 Bean 對象 } else { return (T)parentBeanFactory.getBean(nameToLookup); }複製代碼
方法參數 typeCheckOnly,表示僅僅進行類型檢查獲取 Bean 對象。若是不是僅僅作類型檢查,而是建立 Bean 對象,則須要調用 AbstractBeanFactory#markBeanAsCreated(String beanName) 方法,進行記錄。代碼以下:
//AbstractBeanFactory.java // beanName -> RootBeanDefinition private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256); private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256)); if (!typeCheckOnly) { markBeanAsCreated(beanName); } protected void markBeanAsCreated(String beanName) { // 沒有建立 if (!this.alreadyCreated.contains(beanName)) { // 加上全局鎖 synchronized (this.mergedBeanDefinitions) { // 再次檢查一次:DCL 雙檢查模式 if (!this.alreadyCreated.contains(beanName)) { // 從 mergedBeanDefinitions 中刪除 beanName,並在下次訪問時從新建立它。 clearMergedBeanDefinition(beanName); // 添加到已建立 bean 集合中 this.alreadyCreated.add(beanName); } } } } protected void clearMergedBeanDefinition(String beanName) { this.mergedBeanDefinitions.remove(beanName); } 複製代碼
//AbstractBeanFactory.java // 從容器中獲取 beanName 相應的 GenericBeanDefinition 對象,並將其轉換爲 RootBeanDefinition 對象 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 檢查給定的合併的 BeanDefinition checkMergedBeanDefinition(mbd, beanName, args);複製代碼
調用 AbstractBeanFactory#getMergedLocalBeanDefinition(String beanName) 獲取 RootBeanDefinition 對象。代碼以下:
//AbstractBeanFactory.java // beanName -> RootBeanDefinition private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256); protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException { // 快速從緩存中獲取,若是不爲空,則直接返回 RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); if (mbd != null) { return mbd; } // 若是返回的 BeanDefinition 是子類 bean 的話,則合併父類相關屬性 return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); } 複製代碼
// DefaultListableBeanFactory.java private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); // AbstractBeanFactory.java @Override public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { BeanDefinition bd = this.beanDefinitionMap.get(beanName); if (bd == null) { if (logger.isTraceEnabled()) { logger.trace("No bean named '" + beanName + "' found in " + this); } throw new NoSuchBeanDefinitionException(beanName); } return bd; }複製代碼
5.