在 Spring源码学习【二】IOC容器的初始化(二)BeanDefinition载入 中,我们分析了BeanDefinition的载入过程,同时也留下了这样一句注释:
// TODO:待深入学习
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, con-tainingBean);
下面来填上这里挖下的坑,这句代码实际上是将XML的Element元素解析为具体BeanDefinition的入口,让我们回到BeanDefinitionParserDelegate类的这个方法中,代码如下:
public class BeanDefinitionParserDelegate {
...
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 获得class属性
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
// 获得parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 创建一个具体的BeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析BeanDefinition属性
// 比如:singleton、scope、abstract、lazy-init、autowire等
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析<meta/>元素
parseMetaElements(ele, bd);
// 解析<lookup-method/>元素
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析<replace-method/>元素
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析<contructor-args/>元素
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;
}
}
在上面的代码中可以看到,创建了一个BeanDefinition,然后根据XML资源中的配置解析相关的属性配置,并设置到BeanDefinition,这里理解起来是比较简单的,我们需要重点关注parsePropertyElements这个方法,这个方法中实现了解析<bean>元素下的<property>元素,代码如下:
public class BeanDefinitionParserDelegate {
...
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
// 获得bean元素下的子节点
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 解析property属性
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
parsePropertyElement((Element) node, bd);
}
}
}
public void parsePropertyElement(Element ele, BeanDefinition bd) {
...
// 重点关注这里
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
// 将解析后的property添加到BeanDefinition中
bd.getPropertyValues().addPropertyValue(pv);
...
}
@Nullable
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element";
// <property>下仅允许一个子元素
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);
}
// 有ref属性,即引用其他bean
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;
}
// 有value属性,即普通字符串
else if (hasValueAttribute) {
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}
// 有子元素标签,如<list>、<array>等
else if (subElement != null) {
return parsePropertySubElement(subElement, bd);
}
else {
error(elementName + " must specify a ref or value", ele);
return null;
}
}
@Nullable
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
// 非默认命名空间
if (!isDefaultNamespace(ele)) {
return parseNestedCustomElement(ele, bd);
}
// bean嵌套
else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
}
// bean引用
else if (nodeNameEquals(ele, REF_ELEMENT)) {
String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
toParent = true;
if (!StringUtils.hasLength(refName)) {
error("'bean' or 'parent' is required for <ref> element", ele);
return null;
}
}
if (!StringUtils.hasText(refName)) {
error("<ref> element contains empty target attribute", ele);
return null;
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(extractSource(ele));
return ref;
}
// id引用
else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
return parseIdRefElement(ele);
}
// 普通字符串
else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
return parseValueElement(ele, defaultValueType);
}
// NULL
else if (nodeNameEquals(ele, NULL_ELEMENT)) {
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);
}
// Map
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;
}
}
}
最终,解析处理落在了parseXXElement方法上,这一系列方法实现了对各种元素的解析,我们以集合元素的解析为例看一看具体的解析方式,代码如下:
public class BeanDefinitionParserDelegate {
...
/**
* 解析Array元素
*/
public Object parseArrayElement(Element arrayEle, @Nullable BeanDefinition bd) {
String elementType = arrayEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
NodeList nl = arrayEle.getChildNodes();
ManagedArray target = new ManagedArray(elementType, nl.getLength());
target.setSource(extractSource(arrayEle));
target.setElementTypeName(elementType);
target.setMergeEnabled(parseMergeAttribute(arrayEle));
parseCollectionElements(nl, target, bd, elementType);
return target;
}
/**
* 解析List元素
*/
public List<Object> parseListElement(Element collectionEle, @Nullable BeanDefinition bd) {
String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
NodeList nl = collectionEle.getChildNodes();
ManagedList<Object> target = new ManagedList<>(nl.getLength());
target.setSource(extractSource(collectionEle));
target.setElementTypeName(defaultElementType);
target.setMergeEnabled(parseMergeAttribute(collectionEle));
parseCollectionElements(nl, target, bd, defaultElementType);
return target;
}
/**
* 解析子元素并添加到集合中
*/
protected void parseCollectionElements(NodeList elementNodes, Collection<Object> target, @Nullable BeanDefinition bd, String defaultElementType) {
for (int i = 0; i < elementNodes.getLength(); i++) {
Node node = elementNodes.item(i);
// 这里会解析子元素,比如我们list的子元素是value,那么最终会添加一个字符串到集合中
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
}
}
}
}
到这里,我们发现最终将集合property解析为ManagedXXX对象,并将其添加到了BeanDefinition中。这里的ManagedXXX是对集合类的进一步封装,我们可以参照ManagedArray的类继承图,如下所示:
OK,到这里BeanDefinition的解析就简略分析完了,最终在BeanDefinition以ManagedXXX对象存在的各个Property将会在依赖注入的过程中继续发挥作用