解析子元素constructor-arg

对构造函数的解析是非常常用的。

 

上面的配置时spring构造函数配置中最基础的配置,实现的功能就是对User自动寻找对应的构造函数,并在初始化的时候将设置得参数传入进去。

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

遍历所有子元素,提取所有constructor-arg,然后进行解析,但是具体的解析却被放置在了另一个函数parseConstructorArgElement中,具体代码如下:

public void parseConstructorArgElement(Element ele, BeanDefinition bd) {String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);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));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)) {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 {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();}}}

首先是提取constructor-arg上必要的属性(index、type、name)。

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

(1)解析constructor-arg的子元素

(2)使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素

(3)将type、name和index属性一并封装在ConstructorArgumentValues.ValueHolder类型中并添加至当前BeanDefinition的ConstructorArgumentValues的indexedArgumentValues属性中

如果没有指定index属性,那么操作步骤如下:

(1)解析constructor-arg的子元素

(2)使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素

(3)将type、name和index属性一并封装在ConstructorArgumentValues.ValueHolder类型中并添加至当前BeanDefinition的ConstructorArgumentValues的genericArgumentValues属性中

那么了解整个流程后,我们尝试着进一步了解解析构造函数配置中子元素的过程,进入parsePropertyValue:

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {String elementName = (propertyName != null) ?" element for property '" + propertyName + "'" :" element";// Should only have one child element: ref, value, list, etc.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;}}}boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);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) {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) {TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));valueHolder.setSource(extractSource(ele));return valueHolder;}else if (subElement != null) {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;}}

从代码上来看,对构造函数中属性元素的解析,经历了以下几个过程。

(1)略过description或者meta

(2)提取constructor-arg上的ref和value属性,以便于根据规则验证正确性。

(3)ref属性的处理。使用RuntimeBeanReference封装对应的ref名称。

(4)value属性的处理。使用TypedStringValue封装

(5)子元素的处理

parsePropertySubElement中实现了对各种子元素的分类处理。

public Object parsePropertySubElement(Element ele, BeanDefinition bd) {return parsePropertySubElement(ele, bd, null);}
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {if (!isDefaultNamespace(ele)) {return parseNestedCustomElement(ele, bd);}else if (nodeNameEquals(ele, BEAN_ELEMENT)) {BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);if (nestedBd != null) {nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);}return nestedBd;}else if (nodeNameEquals(ele, REF_ELEMENT)) {// A generic reference to any name of any bean.String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);boolean toParent = false;if (!StringUtils.hasLength(refName)) {// A reference to the id of another bean in the same XML file.refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);if (!StringUtils.hasLength(refName)) {// A reference to the id of another bean in a parent context.refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);toParent = true;if (!StringUtils.hasLength(refName)) {error("'bean', 'local' or 'parent' is required for  element", ele);return null;}}}if (!StringUtils.hasText(refName)) {error(" element contains empty target attribute", ele);return null;}RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);ref.setSource(extractSource(ele));return ref;}else if (nodeNameEquals(ele, IDREF_ELEMENT)) {return parseIdRefElement(ele);}else if (nodeNameEquals(ele, VALUE_ELEMENT)) {return parseValueElement(ele, defaultValueType);}else if (nodeNameEquals(ele, NULL_ELEMENT)) {// It's a distinguished null value. Let's wrap it in a TypedStringValue// object in order to preserve the source location.TypedStringValue nullHolder = new TypedStringValue(null);nullHolder.setSource(extractSource(ele));return nullHolder;}else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {return parseArrayElement(ele, bd);}else if (nodeNameEquals(ele, LIST_ELEMENT)) {return parseListElement(ele, bd);}else if (nodeNameEquals(ele, SET_ELEMENT)) {return parseSetElement(ele, bd);}else if (nodeNameEquals(ele, MAP_ELEMENT)) {return parseMapElement(ele, bd);}else if (nodeNameEquals(ele, PROPS_ELEMENT)) {return parsePropsElement(ele);}else {error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);return null;}}



本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部