上一章,在解析bean标签的时候,还剩余两个方法没有深入

  1. parseBeanDefinitionElement()
  2. registerBeanDefinition()

前者用于解析bean标签中的元素,后者用于将解析得到的BeanDefinition注册到IOC。前者又分为几个步骤:

  1. 处理id、name属性,parseBeanDefinitionElement()
  2. 处理其他属性
  3. 处理bean标签下的子标签。constructor-arg、property…

处理id、name属性

解析bean的配置信息,spring会单独对id、name进行处理,如果没有配置,则会生成唯一的值用来注册。而这整个过程交由BeanDefinitionParserDelegate实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// 重载后,所调用的方法
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 获取bean的id属性
String id = ele.getAttribute(ID_ATTRIBUTE);
// 获取bean的name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

// 将bean的name属性,分割后存入alias中
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}

//如果id属性没有设置,则使用alias中的第一个
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}

// 检查bean的id、alias,是否存在重复
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}

// 对bean标签中其他属性进行解析
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
// 如果bean标签中,没有配置id、name,也没有包含子元素
// 则为该bean生成一个唯一的beanName用于注册
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
} else {
// 如果bean标签中,没有配置id、name,包含子元素
// 则将解析的Bean使用别名向IOC中注册
beanName = this.readerContext.generateBeanName(beanDefinition);
// 为了解析bean使用别名注册时,向后兼容
// Spring 1.2/2.0 给别名添加后缀
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);
}

// 加载失败返回null
return null;
}

处理其他属性

对id、name,做完默认处理之后,则会对bean标签的其他属性进行解析,并将其set到BeanDefinition对象中,这里都只是初始化BeanDefinition,不会真正实例化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {

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

// 获取class属性,这里只是记录,放入BeanDefinition,不会实例化。
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 {
// new 一个 BeanDefinition 对象,将className, parent放入对象中
AbstractBeanDefinition bd = createBeanDefinition(className, parent);

// 初始化一些其他属性,放入BeanDefinition中,如:singleton, scope, abstract, lazy-init....
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

// 解析bean标签的meta(元信息)属性解析
parseMetaElements(ele, bd);
// 解析bean标签的lookup-method属性解析
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析bean标签的replace-method属性解析
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

// 解析构造方法
parseConstructorArgElements(ele, bd);
// 解析bean标签下,property标签
parsePropertyElements(ele, bd);
// 解析bean标签的qualifier属性解析
parseQualifierElements(ele, bd);

// 解析bean所需的资源和依赖对象
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));

return bd;
} catch (ClassNotFoundException ex) {
...
} finally {
this.parseState.pop();
}

return null;
}

解析property标签

bean标签下的子标签很多很多,有一些我还没用过,看了源码才知道有这些东西,汗颜。挑一个内容多点property继续看一下。整理一下步骤,如下:

  1. 遍历所有子标签,判断是否property标签,则往下解析
  2. 解析name属性,以及重名处理
  3. 解析property子标签,如果是ref、value,则保存其引用,其他的list、array、map、等标签,继续解析
  4. 回到第2点的方法中,将其保存到BeanDefinition中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
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)) {
// 开始解析property标签
parsePropertyElement((Element) node, bd);
}
}
}

// 解析标签中的属性
public void parsePropertyElement(Element ele, BeanDefinition bd) {
// 获取名字
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
// 如果一个bean中,配置两个property标签,他们名字相同,则不加载
// 即:如果一个bean中配置两个名字相同的property标签,则只有第一个生效。
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
// 解析property标签中其他属性,如:ref、value等...
Object val = parsePropertyValue(ele, bd, propertyName);
// 将name和各个属性值封装成PropertyValue对象
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
// 将其保存到BeanDefinition中
bd.getPropertyValues().addPropertyValue(pv);
} finally {
this.parseState.pop();
}
}

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

// 获取当前property有子标签,只能是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 {
// 当前property包含的子元素
subElement = (Element) node;
}
}
}

// 判断属性值是ref还是value,不允许既是ref又是value
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) {
// 如果是ref,创建一个对象RuntimeBeanReference,封装ref
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
// 设置这个ref数据对象被当前对象所引用
ref.setSource(extractSource(ele));
return ref;
} else if (hasValueAttribute) {
// 如果是value,创建一个TypedStringValue对象,封装value
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
// 设置这个value的数据对象,被当前对象所引用
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;
}
}

property子标签的子标签还很多,都在parsePropertySubElement()中解析,比如idref、value、array、set、map、props等,这里不能一一贴出来了,到了这里相信理解下面的子标签也不难。