glmapper

Spring源码系列:BeanDefinition载入(中)

字数统计: 837阅读时长: 3 min
2018/11/10 Share

上一篇是将Bean的解析注册流程进行了梳理,对于一些细节问题没有进行细究,比如说元素属性值的处理,构造函数的处理等等。本篇就学习记录一下相关点。

首先来看下是在哪个地方具体生成BeanDefinitiond的。下面是方法请求的顺序。

    1. DefaultBeanDefinitionDocumentReader.parseDefaultElement
    1. DefaultBeanDefinitionDocumentReader.processBeanDefinition
    1. BeanDefinitionParserDelegate.parseBeanDefinitionElement

关于元素的解析绝大多数都是在BeanDefinitionParserDelegate及其子类中完成的。OK,来看下parseBeanDefinitionElement这个方法:

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
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {

this.parseState.push(new BeanEntry(beanName));
String className = null;
//在这里是读取<bean>的class名字,然后载入到BeanDefinition中,并未做实例化
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}

try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//生成BeanDefinition对象
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析当前bean的属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//设置description信息
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//对bean的元素信息进行解析
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析bean的构造函数设置
parseConstructorArgElements(ele, bd);
//解析property设置
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);

bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));

return bd;
}
//异常1:ClassNotFoundException
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
//异常2:NoClassDefFoundError
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;
}

此处我们以解析property为例,看下具体的处理细节:

1
2
3
4
5
6
7
8
9
10
11
12
13
//解析给定bean元素的属性子元素。
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)) {
parsePropertyElement((Element) node, bd);
}
}
}

接着是执行具体property,在parsePropertyElement中完成:

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
//解析一个property元素。
public void parsePropertyElement(Element ele, BeanDefinition bd) {
//首先获取到property的名称
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
//检查是否有name
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
//验证在同一个bean中存在同名的property,存在的话就不解析了,直接返回
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
//解析出property的值
Object val = parsePropertyValue(ele, bd, propertyName);
//封装成PropertyValue对象
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}

在parsePropertyValue中,是对所有的property子元素进行具体解析的。我们知道property中除了单值之外,还会包括如:list,set,map,prop等集合元素;这些都会被封装成对应的Managerd对象。比如:ManagedList等。不同的集合类型页同样对应一种解析方法,比如解析list的是使用parseListElement。这些解析都是在BeanDefinitionParserDelegate类中完成的。这个后面我会抽一篇来学习BeanDefinitionParserDelegate这个类。

Bean的载入过程就是这样通过层层解析来完成的,但是对于目前的Ioc容器来说,仅仅是完成了对Bean对象管理的一些数据准备工作,也就是初始化工作,目前的BeanDefginiton中包含的就是一些静态的配置信息,Bean的实例化还没有进行,这个实例化的过程是在依赖注入时候完成的。

原文作者:GuoLei Song

原文链接:http://www.glmapper.com/2018/11/10/spring-series-bd-loaded-2/

发表日期:November 10th 2018, 2:08:00 pm

更新日期:December 14th 2019, 10:54:44 am

版权声明:转载请注明出处

CATALOG