1. 程式人生 > 實用技巧 >Spring原始碼03---parseDefaultElement

Spring原始碼03---parseDefaultElement

首先讓我們回到https://www.cnblogs.com/xiaomaomao/p/14106990.html文末的 parseBeanDefinitions方法,這個方法主要是解析 beans 標籤下面預設的標籤(beans、import、alias、bean)

程式碼塊一、parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

// DefaultBeanDefinitionDocumentReader 類中的方法
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	// 1、判斷當前是否是預設的名稱空間, Spring 配置檔案預設的名稱空間如下:
	// xmlns="http://www.springframework.org/schema/beans" ,因為它不包含字首 xnlns:字首
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    // 1.1、解析預設名稱空間下面的預設元素,包括 import、alias、beans、bean ---- (詳情見程式碼塊二)
                    parseDefaultElement(ele, delegate);
                }
                else {
                    // 1.2、解析預設名稱空間下面的自定義元素,包括 context、tx... 等
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        // 2、解析自定義名稱空間下的元素
        delegate.parseCustomElement(root);
    }
}

本文主要是為了弄清楚 Spring 是如何解析這些預設的元素的,對應的程式碼是parseDefaultElement(ele, delegate), 這裡麵包含了 Spring beans 標籤下的所有預設的標籤的解析,包括我們最常用,也最重要的 bean 標籤的解析

程式碼塊二、parseDefaultElement(ele, delegate)

// DefaultBeanDefinitionDocumentReader 類中的方法
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
	// 1、解析 import 標籤
	if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
		importBeanDefinitionResource(ele);
	}
	// 2、解析 alias 標籤
	else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
		processAliasRegistration(ele);
	}
	// 3、解析 bean 標籤,這個是我們最常用也最核心的,因為我們在 Spring 配置檔案中配置最多的就是 bean 標籤
	// 注意:這裡解析的是 beans 標籤中的一個 bean 標籤
	// 我們這裡就著重看一下是如何解析 bean 標籤的 ---- (詳細見程式碼塊三)
	else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
		processBeanDefinition(ele, delegate);
	}
	// 4、解析 beans 標籤
	else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
		// 4.1、遞迴呼叫,因為預設的名稱空間是 beans , beans 標籤中是可以巢狀 beans 標籤的
		// 所以需要遞迴呼叫解析 beans 標籤裡面的 beans 標籤裡面的標籤
		doRegisterBeanDefinitions(ele);
	}
}

程式碼塊三、processBeanDefinition(ele, delegate)

// DefaultBeanDefinitionDocumentReader 類中的方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 1、解析一個 bean 標籤,並且將解析好的資料封裝在 BeanDefinitionHolder 物件中 ---- (詳情見程式碼塊四)
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		// 2、若存在預設標籤的子節點下再有自定義屬性,需要再次對自定義標籤再進行解析(基本不用,不做深入解析)
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 3、註冊 BeanDefinition ---- (詳情見程式碼塊八)
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// 4、傳送註冊事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

在解析 bean 標籤之前,我們先去看一下我們用的最多的 bean 標籤,它裡面到底可以配置什麼資訊.

bean 標籤中可以配置的屬性如下:

bean 標籤中可以配置的子標籤如下:

在執行 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele) 這句程式碼之前,我們需要去看一下BeanDefinitionHolder 這個類,開啟這個類,可以發現這個類總共就只有三個屬性, beanName、aliases、beanDefinition ,其中最重要的就是 beanDefinition,它封裝的是 bean 定義資訊,也就是它可以封裝 bean 標籤中的除了 id 、name屬性之外的所有屬性,以及封裝 bean 標籤下面的子標籤中的資料資訊

然後我們再去看一下 BeanDefinition 這個類,並且結合上圖中的 bean 標籤裡面可以配置的屬性值一起看,我們會發現, BeanDefiniton 實際上可以看做是對應 bean 標籤的一個例項.

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
	// 1、預設的 scope 只支援 singleton 和 prototype 兩種,
	// request, session, globalSession, application, websocket ... 這些屬於 web 的擴充套件
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
	// 2、應用的角色
	int ROLE_APPLICATION = 0;
	// 3、支援的角色
	int ROLE_SUPPORT = 1;
	// 4、基礎架構角色
	int ROLE_INFRASTRUCTURE = 2;
	// 5、獲取父 bean ,這裡的父 bean ,不是 java 中繼承關係的父類,它代表的是繼承父 bean 中的屬性
	// 對應的是 bean 標籤中的 parent 屬性,定義父 bean 僅僅是為了繼承父 bean 的屬性而已,子 bean 和
	// 父 bean 不需要存在繼承關係
	String getParentName();
	// 6、設定 Bean 的類名稱,將來是要通過反射來生成例項的
	void setBeanClassName(String beanClassName);
	String getBeanClassName();
	// 7、設定 bean 的 scope 屬性
	void setScope(String scope);
	String getScope();
	void setLazyInit(boolean lazyInit);
	// 8、設定是否懶載入初始化
	boolean isLazyInit();
	// 9、設定該 Bean 依賴的所有的 Bean ,注意:這裡的依賴不是指屬性依賴(如 @Autowire 標記的)
	// 而是 bean 標籤裡面的 depends-on="" 屬性設定的值.
	void setDependsOn(String... dependsOn);
	String[] getDependsOn();
	void setAutowireCandidate(boolean autowireCandidate);
	// 10、是否可以通過 @Atuowired 自動裝配
	boolean isAutowireCandidate();
	void setPrimary(boolean primary);
	// 11、是否是主要的,同一介面的多個實現,如果不指定名字的話, Spring 會優先選擇設定 primary 為 true 的 bean
	boolean isPrimary();
	// 12、設定工廠 bean 的名稱,在 Spring 中,不是所有的 bean 都是通過反射生成的,也可以通過工廠 bean 來生成
	void setFactoryBeanName(String factoryBeanName);
	String getFactoryBeanName();
	// 13、設定工廠 bean 的方法名
	void setFactoryMethodName(String factoryMethodName);
	String getFactoryMethodName();
	// 14、構造引數注入值
	ConstructorArgumentValues getConstructorArgumentValues();
	// 15、Property 屬性注入值
	MutablePropertyValues getPropertyValues();
	boolean isSingleton();
	boolean isPrototype();
	// 16、如果這個 Bean 是被設定為 abstract ,那麼不能例項化,常用於作為父 bean 用於繼承,其實也很少用......
	boolean isAbstract();
	int getRole();
	String getDescription();
	String getResourceDescription();
	BeanDefinition getOriginatingBeanDefinition();
}

看完了BeanDefinitionHolder 和 BeanDefinition,我們接著回到程式碼吧

程式碼塊四、parseBeanDefinitionElement(ele)

// BeanDefinitionParserDelegate 類中的方法
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
	// 1、獲取該 bean 標籤中的 id 屬性值
	String id = ele.getAttribute(ID_ATTRIBUTE);
	// 2、獲取 bean 標籤的 name 屬性值
	String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
	// 3、如果 bean 標籤中配置了<bean name="m1,m2;m3;m4" class="com.xiaomaomao.entity.Mango" >
	// 它會使用 , ; 進行分割,並且將分割後的 m1 m2 m3 m4 存入 List 集合 aliases 中
	List<String> aliases = new ArrayList<String>();
	if (StringUtils.hasLength(nameAttr)) {
		String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
		aliases.addAll(Arrays.asList(nameArr));
	}
	// 4、將 id 值賦值給 beanName 屬性
	String beanName = id;
	// 5、如果 bean 標籤中沒有配置 id 屬性,只配置了 name 屬性
	if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
		// 5.1、那麼就將 name 屬性的第一個值作為 beanName , 剩下的作為 別名
		beanName = aliases.remove(0);
		if (logger.isDebugEnabled()) {
			logger.debug("No XML 'id' specified - using '" + beanName +
					"' as bean name and " + aliases + " as aliases");
		}
	}

	if (containingBean == null) {
		// 6、校驗 beanName 和 aliases 的唯一性
		checkNameUniqueness(beanName, aliases, ele);
	}
	// 7、解析 bean 定義元素 ---- (詳情見程式碼塊五)
	AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	if (beanDefinition != null) {
		// 8、如果 bean 標籤中既沒有配置 id 也沒有配置 name 屬性
		// <bean class="com.xiaomaomao.entity.Mango">
		if (!StringUtils.hasText(beanName)) {
			try {
				// 8.1、如果包含內部 bean 的情況下
				if (containingBean != null) {
					beanName = BeanDefinitionReaderUtils.generateBeanName(
							beanDefinition, this.readerContext.getRegistry(), true);
				}
				else {
					// 8.2 、不包含內部 bean 的情況下, Spring 會根據自己的規則生成 beanName
					// beanName : com.xiaomaomao.entity.Mango#0
					beanName = this.readerContext.generateBeanName(beanDefinition);
					// 8.3、使用 beanClassName 作為別名
					// beanClassName : com.xiaomaomao.entity.Mango
					String beanClassName = beanDefinition.getBeanClassName();
					if (beanClassName != null &&
							beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
							!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
						aliases.add(beanClassName);
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Neither XML 'id' nor 'name' specified - " +
							"using generated bean name [" + beanName + "]");
				}
			}
			catch (Exception ex) {
				error(ex.getMessage(), ele);
				return null;
			}
		}
		// 9、將存放所有別名的 List 集合轉化為 String 型別的陣列
		String[] aliasesArray = StringUtils.toStringArray(aliases);
		// 10、返回 BeanDefinitionHolder 物件
		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
	}
	return null;
}

程式碼塊五、parseBeanDefinitionElement(ele, beanName, containingBean)

// BeanDefinitionParserDelegate 類中的方法
public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) {
	// 1、將 beanName 封裝進 BeanEntry 的 beanDefinitionName 屬性中,然後再存入本類的 ParseState 中
	this.parseState.push(new BeanEntry(beanName));

	String className = null;
	// 2、如果 bean 標籤中配置了 class 屬性,獲取到 class 屬性配置的值
	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
	}
	
	try {
		String parent = null;
		// 3、判斷 bean 標籤中是否配置了 parent 屬性
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}
		// 4、建立一個可以承載 bean 標籤資料的 AbstractBeanDefinition 物件,並設定 beanClass 屬性 ---- (詳情見程式碼塊六)
		AbstractBeanDefinition bd = createBeanDefinition(className, parent);
		// 5、解析 bean 標籤的剩餘屬性 ---- (詳情見程式碼塊七)
		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
		// 6、封裝 description 屬性
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
		// 7、解析 bean 標籤裡面的 meta 標籤
		parseMetaElements(ele, bd);
		// 8、解析 bean 標籤裡面的 lookup - method 標籤
		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
		// 9、解析 bean 標籤裡面的 replace - method 標籤
		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
		
		// 10、解析 bean 標籤裡面的 constructor-arg 標籤,這個標籤很重要,當我們使用有引數構造方法注入值的時候使用該標籤
		// 對 bean 物件裡面的屬性賦值,如果沒有有引數構造方法,那麼會報錯
		parseConstructorArgElements(ele, bd);
		// 11、解析 bean 標籤裡面的 property 標籤,這個標籤也很重要,使用 無引數構造方法 和 setxxx 方法對 bean 物件進行賦值
		parsePropertyElements(ele, bd);
		
		// 12、解析 bean 標籤裡面的 qualifier 標籤 
		parseQualifierElements(ele, bd);
		// 13、設定當前 Spring 配置檔案的資源路徑
		bd.setResource(this.readerContext.getResource());
		bd.setSource(extractSource(ele));

		return bd;
	}
	catch (ClassNotFoundException ex) {
		error("Bean class [" + className + "] not found", ele, ex);
	}
	catch (NoClassDefFoundError err) {
		error("Class that bean class [" + className + "] depends on not found", ele, err);
	}
	catch (Throwable ex) {
		error("Unexpected failure during bean definition parsing", ele, ex);
	}
	finally {
		// 14、移除 ParseState 中之前存入的 BeanDefinitionName
		this.parseState.pop();
	}

	return null;
}

程式碼塊六、createBeanDefinition(className, parent)

// BeanDefinitionParserDelegate 類中的方法
protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
		throws ClassNotFoundException {

	return BeanDefinitionReaderUtils.createBeanDefinition(
			parentName, className, this.readerContext.getBeanClassLoader());
}

// BeanDefinitionReaderUtils 類中的方法
public static AbstractBeanDefinition createBeanDefinition(
		String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
	// 1、新建一個 GenericBeanDefinition 物件用於承載資料,它是 AbstractBeanDefinition 的子類
	GenericBeanDefinition bd = new GenericBeanDefinition();
	// 2、設定 parentName
	bd.setParentName(parentName);
	// 3、如果 bean 標籤中配置了 class 屬性
	if (className != null) {
		if (classLoader != null) {
			// 3.1、如果 classLoader 不為空,使用反射構建出 BeanClass ,並設定為 GenericBeanDefinition 的屬性.
			bd.setBeanClass(ClassUtils.forName(className, classLoader));
		}
		else {
			// 3.2、如果 classLoader 為空,將 className 設定為 GenericBeanDefinition 的屬性.
			bd.setBeanClassName(className);
		}
	}
	// 4、返回 GenericBeanDefinition 物件
	return bd;
}

程式碼塊七、parseBeanDefinitionAttributes(ele, beanName, containingBean, bd)

// BeanDefinitionParserDelegate 類中的方法
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
		BeanDefinition containingBean, AbstractBeanDefinition bd) {
	// 1、對於 1.0 版本的 singleton 屬性 bean 標籤已經不支援了,如果你想使用,必須要用 scope="singleton" 去宣告
	// 否則會報錯,當然 Spring 預設 bean 的 scope 就是 singleton
	if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
		error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
	}
	// 2、將 bean 標籤中的 scope 屬性對應的值使用 GenericBeanDefinition 物件進行封裝
	else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
		bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
	}
	// 3、在內部bean定義的情況下,從包含bean接受預設值.
	else if (containingBean != null) {
		bd.setScope(containingBean.getScope());
	}
	// 4、GenericBeanDefinition 物件封裝 bean 的 abstract 屬性
	if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
		bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
	}
	// 5、Spring 預設不使用懶載入,如果你想使用懶載入初始化,它的值為 false ,如果需要在 bean 標籤上明確規定為 true
	// <bean id="mango" name="m1,m2;m3;m4" class="com.xiaomaomao.entity.Mango" lazy-init="true">
	String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
	if (DEFAULT_VALUE.equals(lazyInit)) {
		lazyInit = this.defaults.getLazyInit();
	}
	bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
	// 6、封裝 autowire 屬性
	String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
	bd.setAutowireMode(getAutowireMode(autowire));
	// 7、封裝 dependency-check 屬性
	String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
	bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
	// 8、封裝 depends-on 屬性
	if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
		String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
		bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
	}
	// 9、封裝 autowire-candidate 屬性
	String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
	if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
		String candidatePattern = this.defaults.getAutowireCandidates();
		if (candidatePattern != null) {
			String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
			bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
		}
	}
	else {
		bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
	}
	// 10、封裝 primary 屬性
	if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
		bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
	}
	// 11、封裝 init-method 屬性
	if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
		String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
		if (!"".equals(initMethodName)) {
			bd.setInitMethodName(initMethodName);
		}
	}
	else {
		if (this.defaults.getInitMethod() != null) {
			bd.setInitMethodName(this.defaults.getInitMethod());
			bd.setEnforceInitMethod(false);
		}
	}
	// 12 、封裝 destroy-method 屬性
	if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
		String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
		bd.setDestroyMethodName(destroyMethodName);
	}
	else {
		if (this.defaults.getDestroyMethod() != null) {
			bd.setDestroyMethodName(this.defaults.getDestroyMethod());
			bd.setEnforceDestroyMethod(false);
		}
	}
	// 13、封裝 factory-method 屬性
	if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
		bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
	}
	// 14、封裝 factory-bean 屬性
	if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
		bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
	}
	// 15、返回封裝了 bean 標籤中所有屬性的 GenericBeanDefinition 物件
	return bd;
}

讓我們回到 解析一個 bean 標籤開始的位置BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

// DefaultBeanDefinitionDocumentReader 類中的方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 1、解析一個 bean 標籤,並且將解析好的資料封裝在 BeanDefinitionHolder 物件中 ---- (詳情見程式碼塊四)
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		// 2、若存在預設標籤的子節點下再有自定義屬性,需要再次對自定義標籤再進行解析(基本不用,不做深入解析)
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 3、註冊 BeanDefinition ---- (詳情見程式碼塊八)
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// 4、傳送註冊事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

到這裡為止整個BeanDefinitionHolder 物件就全部解析出來了,裡面封裝了 beanName、aliases、以及 BeanDefinition 物件.

程式碼塊八、registerBeanDefinition(bdHolder, getReaderContext().getRegistry())

// BeanDefinitionReaderUtils 類中的方法
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
		throws BeanDefinitionStoreException {

	// 1、獲取 beanName 
	String beanName = definitionHolder.getBeanName();
	// 2、註冊 bean 定義 ---- (詳情見程式碼塊九)
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// 3、獲取所有的別名 ---- (詳情見程式碼塊十一)
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String alias : aliases) {
			// 4、依次獲取每一個別名,然後註冊別名
			registry.registerAlias(beanName, alias);
		}
	}
}

程式碼塊九、registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())

// DefaultListableBeanFactory 類中的方法
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

	Assert.hasText(beanName, "Bean name must not be empty");
	Assert.notNull(beanDefinition, "BeanDefinition must not be null");
	// 1、我們前面建立的是一個 GenericBeanDefinition 的物件用來承載資料
	if (beanDefinition instanceof AbstractBeanDefinition) {
		try {
			// 2、校驗 beanDefinition
			((AbstractBeanDefinition) beanDefinition).validate();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}
	// 3、這裡定義一個 oldBeanDefinition 主要是 bean 是否可以覆蓋,我們在同一個 Spring 配置檔案中是不能定義
	// 兩個相同 bean 的,但是可以在不同的配置檔案中定義相同的 bean ,
	// Spring 預設 bean 可以覆蓋,即如果存在兩個相同名稱的 bean ,後加載的那個 bean 覆蓋先載入的 bean
	BeanDefinition oldBeanDefinition;
	
	// 4、通過 beanName 從 beanDefinitionMap 快取中獲取 beanDefinition
	oldBeanDefinition = this.beanDefinitionMap.get(beanName);
	// 5、如果已經存在了 beanDefinition
	if (oldBeanDefinition != null) {
		// 5.1、Spring 預設是可以 bean 覆蓋的,但是如果設定了不可以進行 bean 覆蓋,那麼就丟擲異常
		if (!isAllowBeanDefinitionOverriding()) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
					"': There is already [" + oldBeanDefinition + "] bound.");
		}
		// 5.2、根據 Role 值進行判斷,ROLE_APPLICATION=0 ROLE_SUPPORT=1 ROLE_INFRASTRUCTURE=2
		else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
			// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
			if (this.logger.isWarnEnabled()) {
				this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
						"' with a framework-generated bean definition: replacing [" +
						oldBeanDefinition + "] with [" + beanDefinition + "]");
			}
		}
		// 5.3、如果前後載入的兩個 beanDefinition 內容不同 (這裡的新、舊 beanDefinition 只是 beanName 相同)
		else if (!beanDefinition.equals(oldBeanDefinition)) {
			if (this.logger.isInfoEnabled()) {
				this.logger.info("Overriding bean definition for bean '" + beanName +
						"' with a different definition: replacing [" + oldBeanDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		else {
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Overriding bean definition for bean '" + beanName +
						"' with an equivalent definition: replacing [" + oldBeanDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		// 5.4、使用新載入的 beanDefinition 覆蓋原先 beanDefinitionMap 快取中的 oldBeanDefinition
		// {beanName:oldBeanDefinition} ----> {beanName:beanDefinition}
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}
	// 6、如果 beanDefinitionMap 快取中不存在 beanName
	else {
		// 7、如果建立 Bean 已經開始了
		if (hasBeanCreationStarted()) {
			// Cannot modify startup-time collection elements anymore (for stable iteration)
			// 7.1、加鎖
			synchronized (this.beanDefinitionMap) {
				// 7.2、將本次傳進來的 beanName 和 BeanDefinition 對映放入 beanDefinitionMap 快取
				this.beanDefinitionMap.put(beanName, beanDefinition);
				// 7.3、將本次傳進來的 beanName 加入beanDefinitionNames 快取
				List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
				updatedDefinitions.addAll(this.beanDefinitionNames);
				updatedDefinitions.add(beanName);
				this.beanDefinitionNames = updatedDefinitions;
				// 7.4、如果 manualSingletonNames 包含 beanName ,將 beanName 從 manualSingletonNames 移除
				if (this.manualSingletonNames.contains(beanName)) {
					Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
					updatedSingletons.remove(beanName);
					this.manualSingletonNames = updatedSingletons;
				}
			}
		}
		// 8、目前在註冊階段,還沒有到建立 bean 階段,我們這裡是初次啟動專案,肯定沒有建立 bean
		else {
			// Still in startup registration phase
			// 8.1、將 beanName beanDefinition 以鍵值對的形式存入 beanDefinitionMap 快取中
			this.beanDefinitionMap.put(beanName, beanDefinition);
			// 8.2、將 beanName 存入 beanDefinitionNames 快取中
			this.beanDefinitionNames.add(beanName);
			// 8.3、移除 manualSingletonNames 快取中的 beanName
			this.manualSingletonNames.remove(beanName);
		}
		this.frozenBeanDefinitionNames = null;
	}
	// 9、如果存在相同 beanName 的 BeanDefinition,並且 beanName 已經存在單例物件,則將該 beanName 對應的快取資訊、單例物件清除,
    // 因為這些物件都是通過 oldBeanDefinition 創建出來的,需要使用新的 BeanDefinition 覆蓋掉
    // 我們需要用新的 BeanDefinition(也就是本次傳進來的 beanDefinition)來建立這些快取和單例物件
	// (詳情見程式碼塊十)
	if (oldBeanDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	}
}

程式碼塊十、resetBeanDefinition(beanName)

// DefaultListableBeanFactory 類中的方法
protected void resetBeanDefinition(String beanName) {
    // Remove the merged bean definition for the given bean, if already created.
    // 1、刪除 beanName 的 mergedBeanDefinitions 快取(如果有的話)
    clearMergedBeanDefinition(beanName);
 
    // Remove corresponding bean from singleton cache, if any. Shouldn't usually
    // be necessary, rather just meant for overriding a context's default beans
    // (e.g. the default StaticMessageSource in a StaticApplicationContext).
    // 2、從單例快取中刪除該 beanName 對應的 bean(如果有的話)
    destroySingleton(beanName);
 
    // Reset all bean definitions that have the given bean as parent (recursively).
    // 3.重置 beanName 的所有子 Bean 定義(遞迴)
    for (String bdName : this.beanDefinitionNames) {
        if (!beanName.equals(bdName)) {
            BeanDefinition bd = this.beanDefinitionMap.get(bdName);
            // 當前遍歷的 BeanDefinition 的 parentName 為 beanName,則遞迴呼叫 resetBeanDefinition 進行重置
            if (beanName.equals(bd.getParentName())) {
                resetBeanDefinition(bdName);
            }
        }
    }
}

程式碼塊十一、resetBeanDefinition(bdName)

// SimpleAliasRegistry 類中的方法
public void registerAlias(String name, String alias) {
	Assert.hasText(name, "'name' must not be empty");
	Assert.hasText(alias, "'alias' must not be empty");
	// 1、如果 beanName 和別名相同,則 alias 無效,從 aliasMap 快取中移除
	if (alias.equals(name)) {
		this.aliasMap.remove(alias);
	}
	else {
		// 2、通過 alias 從 aliasMap 快取中獲取 beanName 
		String registeredName = this.aliasMap.get(alias);
		if (registeredName != null) {
			// 3、校驗通過 alias 獲取到的 beanName 和傳進來的 beanName 是否相等,如果相等,代表已經別名已經註冊了,無需再註冊
			if (registeredName.equals(name)) {
				// An existing alias - no need to re-register
				return;
			}
			// 4、如果不允許別名覆蓋,則丟擲異常
			if (!allowAliasOverriding()) {
				throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
						name + "': It is already registered for name '" + registeredName + "'.");
			}
		}
		// 5、校驗 name 和 alias 是否迴圈引用
		checkForAliasCircle(name, alias);
		// 6、將 alias beanName 的鍵值對存入 aliasMap 快取中
		this.aliasMap.put(alias, name);
	}
}

到這裡,一個 bean 標籤的解析已經完成了,程式碼回到了這裡

總結:

1、我們可以重新梳理一下思路,我們首先將 Spring 配置檔案 xml中的 bean 配置資訊進行了解析,並構建了 AbstractBeanDefinition (GenericBeanDefinition ) 物件來存放所有解析出來的 bean 標籤的所有屬性和 bean 標籤下面的子標籤中的資訊.

2、然後,我們將 AbstractBeanDefinition、beanName、aliasesArray構建成 BeanDefinitionHolder物件並返回.

3、最後,我們通過BeanDefinitionHolder將BeanDefinition和beanName 註冊到BeanFactory中,也就是存放到快取中。

執行完 parseDefaultElement 方法,我們得到了兩個重要的快取:

beanDefinitionNames [beanName] 快取

beanDefinitionMap{beanName:beanDefinition}快取

參考:https://blog.csdn.net/v123411739/article/details/86669952