免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Spring默認(rèn)標(biāo)簽的解析

上一篇文章提到過Spring中的標(biāo)簽包括默認(rèn)標(biāo)簽自定義標(biāo)簽,而兩種標(biāo)簽的用法以及解析方式存在著很大的不同,先說說默認(rèn)標(biāo)簽的解析。
默認(rèn)標(biāo)簽的解析是在parseDefaultElement函數(shù)中進(jìn)行的,分別對import、aliasbeanbeans做了不同的處理。

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);
    }
}

1 bean標(biāo)簽的解析和注冊

進(jìn)入processBeanDefinition(ele, delegate)方法:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

大致邏輯如下:

  1. 委托BeanDefinitionParserDelegateparseBeanDefinitionElement方法進(jìn)行元素解析,返回bhHolder。這個(gè)bdHolder實(shí)例已經(jīng)包含我們配置文件中配置的各種屬性了,例如class、nameid、alias等。
  2. 當(dāng)返回的bdHolder不為空的情況下,若存在默認(rèn)標(biāo)簽的子節(jié)點(diǎn)下再有自定義屬性,還需要再次對自定義標(biāo)簽進(jìn)行解析。
  3. 解析完成后,需要對解析后的bdHolder進(jìn)行注冊,同樣,注冊操作委托給了BeanDefinitionReaderUtilsregisterBeanDefinition方法。
  4. 最后發(fā)出響應(yīng)事件,通知相關(guān)的監(jiān)聽器,這個(gè)bean就加載完成了。

1.1 解析BeanDefinition

我們進(jìn)入到BeanDefinitionDelegate類的parseBeanDefinitionElement方法。

@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
		return parseBeanDefinitionElement(ele, null);
	}

	/**
	 * Parses the supplied {@code <bean>} element. May return {@code null}
	 * if there were errors during parse. Errors are reported to the
	 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
	 */
	@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)) {
      // name屬性也是alias的一種
			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);
		}

    // 對標(biāo)簽其他屬性進(jìn)行解析,如class、parent等
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
          // 如果不存在beanName那么根據(jù)Spring提供的命名規(guī)則為當(dāng)前bean生成
					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);
      // 封裝進(jìn)BeanDefinitionHolder中
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

parseBeanDefinitionElement的主要工作包括如下內(nèi)容:

  1. 提取元素中的id以及name屬性。
  2. 進(jìn)一步解析其他所有屬性并統(tǒng)一封裝至GenericBeanDefinition類型的實(shí)例中。
  3. 如果檢測到bean沒有指定beanName,就用默認(rèn)規(guī)則為此bean生成beanName
  4. 將獲取到的信息封裝到BeanDefinitionHolder的實(shí)例中。

進(jìn)一步查看步驟2中對標(biāo)簽其他屬性的解析過程。

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

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

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

		try {
      // 創(chuàng)建用于承載屬性的AbstractBeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

      // 解析默認(rèn)bean的各種屬性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

      // 解析元數(shù)據(jù)
			parseMetaElements(ele, bd);
      // 解析lookup-method屬性
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      // 解析replaced-method屬性
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

      // 解析構(gòu)造函數(shù)參數(shù)
			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.1.1 解析子元素constructor-arg

舉個(gè)Spring構(gòu)造函數(shù)配置的例子:

<bean id="helloBean" class="com.HelloBean">
  <constructor-arg index="0">
    <value>mutianjie</value>
  </constructor-arg>
  <constructor-arg index="1">
  	<value>你好</value>
  </constructor-arg>
</bean>

上面的配置實(shí)現(xiàn)的功能是對HelloBean自動尋找對應(yīng)的構(gòu)造函數(shù),并在初始化的時(shí)候?qū)⒃O(shè)置的參數(shù)傳入進(jìn)去。對于constructor-arg子元素的解析,Spring是通過parseConstructorArgElements函數(shù)來實(shí)現(xiàn)的,具體代碼如下:

/**
	 * Parse constructor-arg sub-elements of the given bean element.
	 */
	public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
				parseConstructorArgElement((Element) node, bd);
			}
		}
	}

在循環(huán)中,parseConstructorArgElements函數(shù)遍歷了所有的<constructor-arg>標(biāo)簽,提取所有的子元素。具體的解析放在了另一個(gè)函數(shù)parseConstructorArgElement中,該函數(shù)的具體代碼如下:

	/**
	 * Parse a constructor-arg element.
	 */
	public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
    // 提取index屬性
		String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
    // 提取type屬性
		String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
    // 提取name屬性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		if (StringUtils.hasLength(indexAttr)) {
			try {
				int index = Integer.parseInt(indexAttr);
				if (index < 0) {
					error("'index' cannot be lower than 0", ele);
				}
				else {
					try {
						this.parseState.push(new ConstructorArgumentEntry(index));
            // 解析ele對應(yīng)的屬性元素
						Object value = parsePropertyValue(ele, bd, null);
            // 封裝解析出來的元素
						ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
						if (StringUtils.hasLength(typeAttr)) {
							valueHolder.setType(typeAttr);
						}
						if (StringUtils.hasLength(nameAttr)) {
							valueHolder.setName(nameAttr);
						}
						valueHolder.setSource(extractSource(ele));
						if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
              // 不允許重復(fù)指定相同的參數(shù)
							error("Ambiguous constructor-arg entries for index " + index, ele);
						}
						else {
							bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
						}
					}
					finally {
						this.parseState.pop();
					}
				}
			}
			catch (NumberFormatException ex) {
				error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
			}
		}
		else {
      // 沒有index屬性則自動尋找
			try {
				this.parseState.push(new ConstructorArgumentEntry());
				Object value = parsePropertyValue(ele, bd, null);
				ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
				if (StringUtils.hasLength(typeAttr)) {
					valueHolder.setType(typeAttr);
				}
				if (StringUtils.hasLength(nameAttr)) {
					valueHolder.setName(nameAttr);
				}
				valueHolder.setSource(extractSource(ele));
				bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
			}
			finally {
				this.parseState.pop();
			}
		}
	}

根據(jù)以上代碼總結(jié)出來的流程為:

如果配置中指定了index屬性,那么操作步驟如下:

  1. 使用parsePropertyValue方法解析constructor-arg的子元素
  2. 使用ConstructArgumentValues.ValueHolder類型來封裝解析出來的元素
  3. typenameindex屬性一并封裝在ConstructArgumentValues.ValueHolder中,并添加至當(dāng)前BeanDefinitionconstructorArgumentValuesindexedArgumentValue中。

如果配置中未指定index屬性,前兩步操作與指定index屬性的做法相同,但是第三步中,valueHolder會添加至當(dāng)前BeanDefinitionconstructorArgumentValuesgenericArgumentValue中。

在構(gòu)造函數(shù)解析中,解析constructor-arg的子元素使用的是parsePropertyValue方法,它是用來解析某一個(gè)具體的構(gòu)造函數(shù)參數(shù)的。這個(gè)方法的代碼如下:

@Nullable
	public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
		String elementName = (propertyName != null ?
				"<property> element for property '" + propertyName + "'" :
				"<constructor-arg> element");

		// 一個(gè)屬性只能對應(yīng)一種類型,如 ref, value, list等
		NodeList nl = ele.getChildNodes();
		Element subElement = null;
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
					!nodeNameEquals(node, META_ELEMENT)) {
				// Child element is what we're looking for.
				if (subElement != null) {
					error(elementName + " must not contain more than one sub-element", ele);
				}
				else {
					subElement = (Element) node;
				}
			}
		}

    // 解析constructor-arg的ref屬性
		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    // 解析constructor-arg的value屬性
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null)) {
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}

		if (hasRefAttribute) {
      // ref屬性的處理,使用RuntimeBeanReference封裝對應(yīng)的ref名稱
			String refName = ele.getAttribute(REF_ATTRIBUTE);
			if (!StringUtils.hasText(refName)) {
				error(elementName + " contains empty 'ref' attribute", ele);
			}
			RuntimeBeanReference ref = new RuntimeBeanReference(refName);
			ref.setSource(extractSource(ele));
			return ref;
		}
		else if (hasValueAttribute) {
      // value屬性的處理,使用TypedStringValue封裝
			TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
			valueHolder.setSource(extractSource(ele));
			return valueHolder;
		}
		else if (subElement != null) {
      // map、list等子元素的處理,如
      /**
      * <constructor-arg>
      * <map>
      * 	<entry key="key" value="value"/>
      * </map>
      * </constructor-arg>
      */
			return parsePropertySubElement(subElement, bd);
		}
		else {
			// Neither child element nor "ref" or "value" attribute found.
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
	}

值得注意的是,除了refvalue兩種子元素之外,還有嵌套子元素如map、list、array等。這類嵌套子元素的處理在parsePropertySubElement方法中完成,對嵌套子元素進(jìn)行分類處理。

1.1.2 解析子元素property

parsePropertyElement函數(shù)完成了對property屬性的提取。property使用方式如下:

<bean id="test" class="test.TestClass">
	<property name="testStr" value="aaa"/>
</bean>
<!--或者-->
<bean id="a">
	<property name="p">
  	<list>
    	<value>aa</value>
      <value>bb</value>
    </list>
  </property>
</bean>
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Spring是如何解析xml配置的
Spring源碼淺析 -- XML配置文件的載入與解析
訪問控制列表(ACL)
Spring兩種屬性注入方式:set和有參構(gòu)造
spring注入null對象
源碼分析 | 像盜墓一樣分析Spring是怎么初始化xml并注冊bean的
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服