Spring源碼深度解析-bean標籤的解析及註冊


書接上文挖的坑,我們已經知道Spring讀取配置文件後,會將我們的配置文件裏的每一個標籤轉換成對應的Element。Spring將配置文件中的標籤分爲默認標籤和自定義標籤,默認標籤的解析是在parseDefaultElement方法中進行的,這個方法的功能邏輯一目瞭然,分別對4 種不同標籤(import、alias、bean、 beans) 做了不同的處理。

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
	if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
		importBeanDefinitionResource(ele);
	}
	else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
		processAliasRegistration(ele);
	}
	else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
		processBeanDefinition(ele, delegate);
	}
	else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
		// recurse
		doRegisterBeanDefinitions(ele);
	}
}

使用工具類的nodeNameEquals方法,來判斷ele是屬於什麼標籤。

1. bean標籤的解析及註冊

bean標籤的解析最爲重要,所以咱們先分析bean標籤的解析。看一下方法processBeanDefinition(ele, delegate)的源碼。

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//1.將ele轉換成BeanDefinitionHolder bdHolder
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
            //2.對子節點的自定義屬性進行解析
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				//3.根據BeanDefinitionHolder進行註冊bean
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// 4、將bean註冊完成的消息通知監聽器
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

這個方法名起的挺有意思,字面意思,定義bean的過程。Spring一般用process開頭的方法,都是一大塊邏輯的入口方法,這種命名規則可以借鑑一下。即使再多的邏輯,Spring的作者也會分步驟,逐步進行。

  1. 使用工具類BeanDefinitionParserDelegate的parseBeanDefinitionElement的方法進行元素解析,返回BeanDefinitionHolder類型的實例bdHolder。bdHolder就是一個包含beanDefinition、beanName的持有者,它有beanName、beanDefinition、aliases屬性。這個方法就是真正的解析Element,此時bdHolder的beanDefinition就會包含我們配置文件中配置的各種屬性了,例如class、name、id、alias之類的屬性。
  2. 當返回的bdHolder 不爲空的情況下,若存在默認標籤的子節點下再有自定義屬性, 還需要再次對自定義標籤進行解析。
  3. 根據BeanDefinitionHolder進行註冊bean,註冊的功能由BeanDefinitionReaderUtils的
    registerBeanDefinition方法完成。
  4. 最後發出響應事件,通知相關的監昕器,這個bean 已經加載完成了。

1.1 解析Element獲取BeanDefinition

進入BeanDefinitionDelegate類的parseBeanDefinitionElement 方法,Spring通過這個方法將Element裏面的內容解析至BeanDefinitionHolder裏面。

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element)
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
		// 直接調用下面的方法
		return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		//解析id屬性
		String id = ele.getAttribute(ID_ATTRIBUTE);
		//解析name屬性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		//分割name屬性
		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}
		// beanName的默認值是id
		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			// beanName爲一串空格,則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) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		// 解析bean元素,併產生一個beanDefinition!!!
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					// 如果不存在beanName那麼根據spring中提供的命名規則爲當前bean生成對應的beanName
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						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;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

這個方法主要完成的方法如下:

  1. 提取元素中的id及name屬性。
  2. 使用重載的parseBeanDefinitionElement方法,進一步解析其他所有屬性並統一封裝至GenericBeanDefinition 類型的實例中。
  3. 如果檢測到bean沒有指定beanName ,那麼使用默認規則爲此bean 生成beanName。
  4. 將上面獲得的beanDefinition、beanName、別名數組,封裝至BeanDefinitionHolder。
    本方法最重要的目的有兩個,第一,確定全局唯一的beanName。beanName的默認值是id屬性的值;如果id爲null,則默認是name屬性的第一個名字,name屬性可以用,;分隔符進行配置多個;最後,如果沒有指定beanName ,那麼Spring將會按照自己的規則生成beanName。第二,調用重載方法,得到GenericBeanDefinition。下面我們看看重載的parseBeanDefinitionElement。
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

	this.parseState.push(new BeanEntry(beanName));

	String className = null;
	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
	}
	String parent = null;
	if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
		parent = ele.getAttribute(PARENT_ATTRIBUTE);
	}

	try {
		//創建用於承載屬性的AbstractBeanDefinition類型的GenericBeanDefinition
		AbstractBeanDefinition bd = createBeanDefinition(className, parent);
		//硬編碼解析默認bean的各種屬性
		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
		//提取description
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
		//解析子元素meta
		parseMetaElements(ele, bd);
		//解析lookup-method屬性
		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
		//解析replaced-method屬性
		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
		//解析構造函數參數
		parseConstructorArgElements(ele, bd);
		//解析property子元素
		parsePropertyElements(ele, bd);
		//解析qualifier子元素
		parseQualifierElements(ele, bd);

		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 {
		this.parseState.pop();
	}

	return null;
}
  1. 創建用於承載屬性的AbstractBeanDefinition類型的GenericBeanDefinition。
    BeanDefinition是一個接口,是配置文件<bean>元素標籤在容器中的內部表示形式。在Spring 中存在三種常見的實現: RootBeanDefinition、ChildBeanDefinition
    以及GenericBeanDefinition三種實現均繼承了AbstractBeanDefiniton。<bean>元素標籤擁有class 、scope 、lazy-init 等配置屬性, BeanDefinition 則提供了相應的beanClass、scope、lazyInit屬性,BeanDefinition 和<bean>中的屬性是一一對應的。其中
    RootBeanDefinition 是最常用的實現類,它對應一般性的<bean>元素標籤。GenericBeanDefinition 是自2.5 版本以後新加入的bean文件配置屬性定義類,是一站式服務類。
    在配置文件中可以定義父<bean >和子<bean>,父<bean>用RootBeanDefinition 表示,而子<bean>用ChildBeanDefiniton 表示,而沒有父<bean>的<bean>就使用RootBeanDefinition 表示。AbstractBeanDefinition 對兩者共同的類信息進行抽象。
    Spring 通過BeanDefinition 將配置文件中的<bean>配置信息轉換爲容器的內部表示,並將這些BeanDefiniton 註冊到BeanDefinitonRegistry 中。BeanDefinitionRegistrγ 就像是Spring 配置信息的內存數據庫,主要是以map 的形式保存,後續操作直接從BeanDefinitionRegistry中讀取配置信息。
    由此可知,要解析屬性首先要創建用於承載屬性的實例,也就是創建GenericBeanDefinition類型的實例。而代碼createBeanDefinition(className, parent)的作用就是實現此功能。
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#createBeanDefinition
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
			throws ClassNotFoundException {

		return BeanDefinitionReaderUtils.createBeanDefinition(
				parentName, className, this.readerContext.getBeanClassLoader());
	}
org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition
public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setParentName(parentName);
		if (className != null) {
			if (classLoader != null) {
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}

當我們創建了用於承載bean標籤各種屬性的對象後,便可以進行bean標籤的各種屬性解析了。
2. parseBeanDefinitionAttributes 方法是對element 所有元素屬性進行解析,源碼如下。

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
			@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
	//解析scope屬性
	if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
		error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
	}
	else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
		bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
	}
	else if (containingBean != null) {
		// Take default from containing bean in case of an inner bean definition.
		//在嵌入beanDefinition情況下且沒有單獨指定scope屬性則使用父類默認的屬性
		bd.setScope(containingBean.getScope());
	}
	//解析abstract屬性
	if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
		bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
	}
	//解析lazy-init屬性
	String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
	if (isDefaultValue(lazyInit)) {
		lazyInit = this.defaults.getLazyInit();
	}
	bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
	//解析autowire屬性
	String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
	bd.setAutowireMode(getAutowireMode(autowire));
	//解析depends-on屬性
	if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
		String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
		bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
	}
	//解析autowire-candidate屬性
	String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
	if (isDefaultValue(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));
	}
	//解析primary屬性
	if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
		bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
	}
	//解析init-method"屬性
	if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
		String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
		bd.setInitMethodName(initMethodName);
	}
	else if (this.defaults.getInitMethod() != null) {
		bd.setInitMethodName(this.defaults.getInitMethod());
		bd.setEnforceInitMethod(false);
	}
	//解析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);
	}
	//解析factory-method屬性
	if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
		bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
	}
	if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
		bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
	}
	return bd;
}

上面就是Spring把bean標籤的屬性值,set到BeanDefinition中。這些屬性有我們常用的scope、lazy-init、init-method等等。
Spring在上面設置完bean標籤的屬性後,Spring還有子元素meta、lookup-method、replaced-method、constructor-arg、property、qualifier需要解析,這裏就不在分析了,我們只需要知道,這些子標籤定義的功能是需要Spring這些底層的代碼支撐的。至此我們便完成了對XML文檔到GenericBeanDefinition的轉換,也就是說,XML中所有的配置都可以在GenericBeanDefinition的實例類中找到對應的配置。

1.2 解析bean標籤下的自定義標籤

我們回到源碼剛開始的地方
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition方法,1.1節一直在分析
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);這一行代碼,現在我們開始第二行:bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)。
這一行的作用是解析bean標籤下面聲明自定義標籤,將其封裝到BeanDefinition中。這種用法我們在項目中一般不會這樣使用,目前我是沒有遇到過,咱們就忽略吧,感興趣的同學可以去分析一下。

1.3 註冊BeanDefiniton

現在終於得到了我們最終版的BeanDefinition,剩下就是註冊了。註冊的代碼在咱們的
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());完成。

public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

	// 使用beanName做唯一標識進行註冊
	String beanName = definitionHolder.getBeanName();
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// 遍歷別名進行註冊
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String alias : aliases) {
			registry.registerAlias(beanName, alias);
		}
	}
}

解析的beanDefinition都會被註冊到BeanDefinitionRegistry 類型的實例registry中,而對於beanDefinition 的註冊分成了兩部分:通過beanName的註冊以及通過別名的註冊。

1.3.1 通過beanName註冊BeanDefinition

Spring通過beanName註冊BeanDefinition,就是以beanName爲key,beanDefinition對象爲value,這個鍵值對存入到map裏面,另外Spring還做了一些其他的事情。

org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
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");

	if (beanDefinition instanceof AbstractBeanDefinition) {
		try {
			((AbstractBeanDefinition) beanDefinition).validate();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}

	BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
	if (existingDefinition != null) {
		if (!isAllowBeanDefinitionOverriding()) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
					"': There is already [" + existingDefinition + "] bound.");
		}
		else if (existingDefinition.getRole() < beanDefinition.getRole()) {
			// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
			if (logger.isWarnEnabled()) {
				logger.warn("Overriding user-defined bean definition for bean '" + beanName +
						"' with a framework-generated bean definition: replacing [" +
						existingDefinition + "] with [" + beanDefinition + "]");
			}
		}
		else if (!beanDefinition.equals(existingDefinition)) {
			if (logger.isInfoEnabled()) {
				logger.info("Overriding bean definition for bean '" + beanName +
						"' with a different definition: replacing [" + existingDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Overriding bean definition for bean '" + beanName +
						"' with an equivalent definition: replacing [" + existingDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}
	else {
		if (hasBeanCreationStarted()) {
			// 因爲beanDefinitionMap是全局變量,這裏定會存在併發訪問的情況
			synchronized (this.beanDefinitionMap) {
				this.beanDefinitionMap.put(beanName, beanDefinition);
				List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
				updatedDefinitions.addAll(this.beanDefinitionNames);
				updatedDefinitions.add(beanName);
				this.beanDefinitionNames = updatedDefinitions;
				if (this.manualSingletonNames.contains(beanName)) {
					Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
					updatedSingletons.remove(beanName);
					this.manualSingletonNames = updatedSingletons;
				}
			}
		}
		else {
			// Still in startup registration phase
			this.beanDefinitionMap.put(beanName, beanDefinition);
			this.beanDefinitionNames.add(beanName);
			this.manualSingletonNames.remove(beanName);
		}
		this.frozenBeanDefinitionNames = null;
	}

	if (existingDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	}
}

  1. 對AbstractBeanDefinition的校驗,此時的校驗時是對於AbstractBeanDefinition的methodOverrides 屬性的。
  2. 對beanName已經註冊的情況的處理。如果設置了不允許bean的覆蓋,則需要拋出異常,否則直接覆蓋。
  3. 加入map 緩存。
  4. 清除解析之前留下的對應beanName的緩存。

1.3.2 通過別名註冊BeanDefinition

org.springframework.core.SimpleAliasRegistry#registerAlias
public void registerAlias(String name, String alias) {
	Assert.hasText(name, "'name' must not be empty");
	Assert.hasText(alias, "'alias' must not be empty");
	synchronized (this.aliasMap) {
		if (alias.equals(name)) {
			this.aliasMap.remove(alias);
			if (logger.isDebugEnabled()) {
				logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
			}
		}
		else {
			String registeredName = this.aliasMap.get(alias);
			if (registeredName != null) {
				if (registeredName.equals(name)) {
					// An existing alias - no need to re-register
					return;
				}
				if (!allowAliasOverriding()) {
					throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
							name + "': It is already registered for name '" + registeredName + "'.");
				}
				if (logger.isInfoEnabled()) {
					logger.info("Overriding alias '" + alias + "' definition for registered name '" +
							registeredName + "' with new target name '" + name + "'");
				}
			}
			// 校驗會不出產生:別名A1--->A,A--->A1情況,如過出現此情況則,拋出異常,不允許保存別名
			checkForAliasCircle(name, alias);
			this.aliasMap.put(alias, name);
			if (logger.isDebugEnabled()) {
				logger.debug("Alias definition '" + alias + "' registered for name '" + name + "'");
			}
		}
	}
}

  1. alias與beanName相同情況處理。若alias與beanName 名稱相同則不需要處理並刪除掉原有alias。
  2. alias覆蓋處理。若aliasName已經使用並已經指向了另一beanName 則需要用戶的設置
    進行處理。
  3. alias 循環檢查。// 校驗會不出產生:別名A1—>A,A—>A1情況,如過出現此情況則,拋出異常,不允許保存別名
  4. 註冊alias 。

1.4 通知監聽器解析註冊完成的事件

最後一行代碼:
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
Spring運用設計模式中的觀察者模式,將我們重要的事件:bean標籤解析完成生成BeanDefinition,且註冊BeanDefinition完成事件通知給各個觀察者。目前在Spring 中並沒有對此事件做任何邏輯處理。
現在我們的Bean Definition已經被註冊到Map類型的beanDefinitionMap中,剩下的操作,就是根據這map中的BeanDefinition進行創建bean。這個我們以後再開一坑。

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