四、Spring默認標籤之bean標籤的解析及註冊

一、先期準備

參見 三、Spring之解析及註冊 BeanDefinitions 之默認標籤的解析

二、bean 標籤的解析及註冊

(一)調用流程

  1. 首先委託 BeanDefinitionParserDelegate 類的 parseBeanDefinitionElement() 方法進行元素解析,返回 BeanDefinitionHolder 類型的實例 bdHolder,經過這個方法以後,bdHolder 實例已經包含我們配置文件中配置的各種屬性了,例如 class、name、id、alias 之類的屬性
  2. 當返回的 bdHolder 不爲空的情況下若存在默認標籤的子節點下再有自定義屬性,還需要再次對自定義標籤進行解析
  3. 解析完成以後,需要對解析後的 bdHolder 進行註冊,同樣,註冊委託給了 BeanDefinitionReaderUtilsregisterBeanDefinition() 方法
  4. 最後發出響應事件,通知相關的監聽器,這個 bean 已經加載完成
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		/*
		 *    首先委託 BeanDefinitionParserDelegate 類的 parseBeanDefinitionElement() 方法進行元素解析,返回
		 * BeanDefinitionHolder 類型的實例 bdHolder,經過這個方法以後,bdHolder 實例已經包含我們配置文件中配
		 * 置的各種屬性了,例如 class、name、id、alias 之類的屬性
		 */
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			/*
			 *     當返回的 bdHolder 不爲空的情況下若存在默認標籤的子節點下再有自定義屬性,還需要再次對自定義標籤進行
			 * 解析
			 */
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				/*
				 *     解析完成以後,需要對解析後的 bdHolder 進行註冊,同樣,註冊委託給了 BeanDefinitionReaderUtils 的
				 * registerBeanDefinition() 方法
				 */
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			/*
			 *     最後發出響應事件,通知相關的監聽器,這個 bean 已經加載完成
			 */
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}
  • BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)
  1. 抽取元素中的 id 以及 name 屬性
  2. 進一步解析其他所有屬性並統一封裝至 GenericBeanDefinition 類型的實例中
  3. 如果檢測到 bean 沒有指定 beanName,那麼使用默認規則爲此 Bean 生成 beanName
  4. 將獲取到的信息封裝到 BeanDefinitionHolder
	/**
	 * 主要是對屬性 id 以及 name 的解析:
	 * 1.抽取元素中的 id 以及 name 屬性
	 * 2.進一步解析其他所有屬性並統一封裝至 GenericBeanDefinition 類型的實例中
	 * 3.如果檢測到 bean 沒有指定 beanName,那麼使用默認規則爲此 Bean 生成 beanName
	 * 4.將獲取到的信息封裝到 BeanDefinitionHolder 中
	 */
	@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		// 解析 id 屬性
		String id = ele.getAttribute(ID_ATTRIBUTE);
		// 解析 name 屬性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isTraceEnabled()) {
				logger.trace("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		// 解析其他所有子元素,諸如:meta、lookup-method、replaced-method、constructor-arg、property、qualifier
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

		if (beanDefinition != null) {
			// 若不存在 beanName 那麼根據 Spring 中提供的命名規則爲當前 bean 生成對應的 beanName
			if (!StringUtils.hasText(beanName)) {
				try {
					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.isTraceEnabled()) {
						logger.trace("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;
	}
  • BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
  1. 創建用於承載屬性的 AbstractBeanDefinition 類型的 GenericBeanDefinition
  2. 硬編碼解析默認 <bean> 標籤的各種屬性
  3. 解析子元素 meta
  4. 解析子元素 lookup-method
  5. 解析子元素 replaced-method
  6. 解析子元素 constructor-arg
  7. 解析子元素 property
  8. 解析子元素 qualifier

	@Nullable
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

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

		String className = null;
		// 解析 class 屬性
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		// 解析 parent 屬性
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			/*
			 * 創建用於承載屬性的 AbstractBeanDefinition 類型的 GenericBeanDefinition:
			 *     BeanDefinition 是一個接口,在 Spring 中存在三種實現:RootBeanDefinition、ChildBeanDefinition 以及
			 * GenericBeanDefinition 。三種實現均繼承了 AbstractBeanDefinition ,其中 BeanDefinition 是配置文件 <bean>
			 * 元素標籤在容器中的內部表現形式。<bean> 元素標籤擁有 class、scope、lazy-init 等配置屬性,BeanDefinition則
			 * 提供了相應的 beanClass、scope、lazyInit 屬性,BeanDefinition 和 <bean> 中的屬性是一一對應的。
			 */
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			// 硬編碼解析默認 <bean>標籤的各種屬性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			// 提取 description
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			//解析元數據
			parseMetaElements(ele, bd);
			/*
			 * 解析 lookup-method 屬性:
			 *     我們通常稱 lookup-method 爲獲取器注入,獲取注入是一種特殊的方法注入,它是把一個方法聲明爲返回某種類型
			 * 的 bean,但實際要返回的 bean 是在配置文件裏面配置的,此方法可用在設計有些可插拔的功能上,解除程序依賴。
			 * 案例參見書本 P53-54
			 */
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			/*
			 * 解析 replaced-method 屬性:
			 *     方法替換:可以在運行時用心得的方法替換現有的方法。與之前的 look-up 不同的是,replaced-method 不但可以
			 * 動態地替換返回實體 bean,而且還能動態地更改原有方法的邏輯。案例參見書本 P55-56
			 */
			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;
	}
  • BeanDefinitionParserDelegate#createBeanDefinition(@Nullable String className, @Nullable String parentName)
	/*
	 * 創建用於承載屬性的 AbstractBeanDefinition 類型的 GenericBeanDefinition:
	 *     BeanDefinition 是一個接口,在 Spring 中存在三種實現:RootBeanDefinition、ChildBeanDefinition 以及
	 * GenericBeanDefinition 。三種實現均繼承了 AbstractBeanDefinition ,其中 BeanDefinition 是配置文件 <bean>
	 * 元素標籤在容器中的內部表現形式。<bean> 元素標籤擁有 class、scope、lazy-init 等配置屬性,BeanDefinition則
	 * 提供了相應的 beanClass、scope、lazyInit 屬性,BeanDefinition 和 <bean> 中的屬性是一一對應的。
	 */
	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) {
				// 若 classLoader 不爲空,則使用已傳入的 classLoader 同一虛擬機加載類對象,否則只是記錄 className
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}
  • BeanDefinitionParserDelegate#parseBeanDefinitionAttributes(Element ele, String beanName,@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd)
	/**
	 * 對 <bean> 標籤的所有屬性進行解析,例如:scope、lazy-init 等
	 * Apply the attributes of the given bean element to the given bean * definition.
	 * @param ele bean declaration element
	 * @param beanName bean name
	 * @param containingBean containing bean definition
	 * @return a bean definition initialized according to the bean element attributes
	 */
	public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
			@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

		if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
			// singleton 屬性已不再使用,改爲 scope 屬性
			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 屬性,若沒有設置或者設置成其他字符都會被設置爲 false
		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 屬性(depends-on用來指定Bean初始化及銷燬時的順序)
		if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
			String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
			bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
		}

		/*
		 * 解析 autowire-candidate 屬性:
		 *     自動依賴注入大大簡化了我們的工作量,但是也有缺陷,如果一個接口有多個實現類,我們該注入哪一個呢?
		 *     一種方法是設置其中一個bean不參與自動注入:<bean class="shangbo.spring.example38.MessageServiceDBImpl" autowire-candidate="false" />
		 *     另一種方法是全局設定哪些對象不參數自動注入:
		 *     <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"
				default-autowire="byType"
				default-autowire-candidates="messageServiceDBImpl">
		 */
		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 屬性(相當於 @PostConstruct 註解)
		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 屬性(相當於 @PreDestroy 註解)
		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 屬性(詳情解析參見:https://blog.csdn.net/qq_33188563/article/details/82865165)
		if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
			bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
		}
		// 解析 factory-bean 屬性(詳情解析參見:https://blog.csdn.net/qq_33188563/article/details/82865165)
		if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
			bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
		}

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