Spring源碼解析之從處理依賴depends-on

這篇文章分析的代碼:

if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            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 {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            //如果不是僅僅做類型檢查則是創建bean,這裏需要記錄 將beanName緩存在alreadyCreatedz中
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            try {
                // 從容器中獲取 beanName 相應的 GenericBeanDefinition,並將其轉換爲 RootBeanDefinition
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                // 檢查給定的合併的 BeanDefinition
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    //獲取depends-on的屬性值,如果depends-on的值存在 則添加進入dependentBeanMap緩存中
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        try {
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

這段代碼處理的邏輯是:

  • 如果bean是原型模式並處於創建中,則拋出異常。
  • 如果beanDefinitionMap中不存在對應beanName的BeanDefinition,那麼嘗試從parentBeanFactory中加載。
  • 判斷是否檢查類型
  • 從 mergedBeanDefinitions 中獲取 beanName 對應的 RootBeanDefinition
  • 檢查dependes-on依賴

1. isPrototypeCurrentlyInCreation方法

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
		Object curVal = this.prototypesCurrentlyInCreation.get();
		return (curVal != null &&
				(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
	}

Spring對於處於原型模式的正在創建的bean的依賴會拋出異常。

 

2.pareentBeanFactory加載

BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
	//獲取原始name
	String nameToLookup = originalBeanName(name);
	if (parentBeanFactory instanceof AbstractBeanFactory) {
		//加入parentBeanFactory是AbstractBeanFactory類型
		return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
				nameToLookup, requiredType, args, typeCheckOnly);
	}
	else if (args != null) {
		//args不爲空情況下,委託方法
		return (T) parentBeanFactory.getBean(nameToLookup, args);
	}
	else {
		////標準情況下,委託方法
		return parentBeanFactory.getBean(nameToLookup, requiredType);
	}
}

如果beanDefinitionMap沒有包含beanName對應的BeanDefinition,則從parentBeanFactory中加載。

originalBeanName()方法作用:如果name是以&開頭的,那麼beanName也要加上這個標誌。

 

3.類型檢查

參數typeCheckOnly判斷bean是否爲類型檢查獲取bean。如果不是則需要調用markBeanAsCreated()緩存起來.

protected void markBeanAsCreated(String beanName) {
	//判斷已創建是否包含beanName
	if (!this.alreadyCreated.contains(beanName)) {
	    // 獲取全局鎖
		synchronized (this.mergedBeanDefinitions) {
		    //雙重判斷
			if (!this.alreadyCreated.contains(beanName)) {
			     // 從 mergedBeanDefinitions 中刪除 beanName,
                 // 並在下次訪問時重新創建它。
				clearMergedBeanDefinition(beanName);
				// 添加到已創建bean 集合中
				this.alreadyCreated.add(beanName);
			}
		}
	}
}

 

4. 獲取RootBeanDefinition

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

getMergedLocalBeanDefinition():作用主要是將獲取beanName對應的RootBeanDefinition對象

checkMergedBeanDefinition()則是檢查創建的RootBeanDefinition對象。

 

5.處理depends-on

 String[] dependsOn = mbd.getDependsOn();
 if (dependsOn != null) {
     //獲取depends-on的屬性值,如果depends-on的值存在 則添加進入dependentBeanMap緩存中
     for (String dep : dependsOn) {
         if (isDependent(beanName, dep)) {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                     "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
         }
         registerDependentBean(dep, beanName);
         try {
             getBean(dep);
         }
         catch (NoSuchBeanDefinitionException ex) {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                     "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
         }
     }
 }
 // 單例模式下創建bean

處理bean的依賴思路大致是:

  • 獲取depends-on依賴,如果depends-on不爲空,檢查beanName和依賴是否已經存在依賴關係。
  • 如果存在拋出異常,不存在則緩存對應的依賴。

isDependent方法:檢測beaName和dependsOn是否存在已存在依賴。

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
        if (alreadySeen != null && alreadySeen.contains(beanName)) {
            return false;
        }
        //獲取原始的beanName
        String canonicalName = canonicalName(beanName);
        //獲取beaName的依賴集合
        Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
        if (dependentBeans == null) {
            return false;
        }
        //包含,則證明已經處於註冊依賴
        if (dependentBeans.contains(dependentBeanName)) {
            return true;
        }
        //遞歸檢測
        for (String transitiveDependency : dependentBeans) {
            if (alreadySeen == null) {
                alreadySeen = new HashSet<>();
            }
            alreadySeen.add(beanName);
            if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
                return true;
            }
        }
        return false;
    }

registerDependentBean方法註冊bean的依賴關係

public void registerDependentBean(String beanName, String dependentBeanName) {
		String canonicalName = canonicalName(beanName);

		synchronized (this.dependentBeanMap) {
			Set<String> dependentBeans =
					this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
			if (!dependentBeans.add(dependentBeanName)) {
				return;
			}
		}

		synchronized (this.dependenciesForBeanMap) {
			Set<String> dependenciesForBean =
					this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
			dependenciesForBean.add(canonicalName);
		}
	}

將依賴映射關係保存:dependentBeanMap、dependenciesForBeanMap。

最後調用getBean()實例化bean。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章