【Spring源码】IoC之注册BeanDefinitions
在【Spring源码】IoC之加载 BeanDefinition中提到,在核心逻辑方法#doLoadBeanDefinitions(InputSource inputSource, Resource resource) 方法中,中主要是做三件事情:
- 调用
#getValidationModeForResource(Resource resource)方法,获取指定资源(xml)的验证模式。 - 调用
DocumentLoader#loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware)方法,获取 XML Document 实例。 - 调用
#registerBeanDefinitions(Document doc, Resource resource)方法,根据获取的 Document 实例,注册 Bean 信息。
这篇博客主要第 3 步,分析注册 Bean 信息。
获取 XML Document 对象后,会根据该对象和 Resource 资源对象调用 XmlBeanDefinitionReader#registerBeanDefinitions(Document doc, Resource resource) 方法,开始注册 BeanDefinitions 之旅。代码如下:
1 | // AbstractBeanDefinitionReader.java |
<1>处,调用#createBeanDefinitionDocumentReader()方法,实例化 BeanDefinitionDocumentReader 对象。FROM 《Spring 源码深度解析》P16页
定义读取 Document 并注册 BeanDefinition 功能
<2>处,调用BeanDefinitionRegistry#getBeanDefinitionCount()方法,获取已注册的 BeanDefinition 数量。<3>处,调用#createReaderContext(Resource resource)方法,创建 XmlReaderContext 对象。<4>处,调用BeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)方法,读取 XML 元素,注册 BeanDefinition 们。<5>处,计算新注册的 BeanDefinition 数量。
createBeanDefinitionDocumentReader
#createBeanDefinitionDocumentReader(),实例化 BeanDefinitionDocumentReader 对象。代码如下:
1 | /** |
documentReaderClass的默认值为DefaultBeanDefinitionDocumentReader.class。关于它,我们在后续的文章,详细解析。
registerBeanDefinitions
BeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext) 方法,注册 BeanDefinition ,在接口 BeanDefinitionDocumentReader 中定义。代码如下:
1 | public interface BeanDefinitionDocumentReader { |
从给定的 Document 对象中解析定义的 BeanDefinition 并将他们注册到注册表中。方法接收两个参数:
doc方法参数:待解析的 Document 对象。readerContext方法,解析器的当前上下文,包括目标注册表和被解析的资源。它是根据 Resource 来创建的,见下文。
DefaultBeanDefinitionDocumentReader
BeanDefinitionDocumentReader 有且只有一个默认实现类 DefaultBeanDefinitionDocumentReader 。它对 #registerBeanDefinitions(...) 方法的实现代码如下:
DefaultBeanDefinitionDocumentReader 对该方法提供了实现:
1 |
|
<1>处,创建 BeanDefinitionParserDelegate 对象,并进行设置到delegate。BeanDefinitionParserDelegate 是一个重要的类,它负责解析 BeanDefinition。代码如下:FROM 《Spring 源码深度解析》P16
定义解析 XML Element 的各种方法
1
2
3
4
5
6
7
8protected BeanDefinitionParserDelegate createDelegate(
XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {
// 创建 BeanDefinitionParserDelegate 对象
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
// 初始化默认
delegate.initDefaults(root, parentDelegate);
return delegate;
}<2>处,检查<beans />根标签的命名空间是否为空,或者是 http://www.springframework.org/schema/beans 。<2.1>处,判断是否<beans />上配置了profile属性。不了解这块的胖友,可以看下 《Spring3自定义环境配置 》 。<2.2>处,使用分隔符切分,可能有多个 profile 。<2.3>处,判断,如果所有 profile 都无效,则return不进行注册。
<4>处,调用#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法,进行解析逻辑。<3>/<5>处,解析前后的处理,目前这两个方法都是空实现,交由子类来实现。代码如下:1
2
3protected void preProcessXml(Element root) {}
protected void postProcessXml(Element root) {}
parseBeanDefinitions
#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法,进行解析逻辑。代码如下:
1 | /** |
Spring 有两种 Bean 声明方式:
- 配置文件式声明:
<bean id="studentService" class="org.springframework.core.StudentService" />。对应<1>处。 - 自定义注解方式:
<tx:annotation-driven>。对应<2>处。
- 配置文件式声明:
<1>处,如果根节点或子节点使用默认命名空间,调用#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)方法,执行默认解析。代码如下:1
2
3
4
5
6
7
8
9
10
11
12private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // import
importBeanDefinitionResource(ele);
} else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // alias
processAliasRegistration(ele);
} else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // bean
processBeanDefinition(ele, delegate);
} else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // beans
// recurse
doRegisterBeanDefinitions(ele);
}
}<2>处,如果根节点或子节点不使用默认命名空间,调用BeanDefinitionParserDelegate#parseCustomElement(Element ele)方法,执行自定义解析。详细的解析,见后续文章。
createReaderContext
#createReaderContext(Resource resource) 方法,创建 XmlReaderContext 对象。代码如下:
1 | private ProblemReporter problemReporter = new FailFastProblemReporter(); |
小结
至此,XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource inputSource, Resource resource) 方法中,做的三件事情已经全部分析完毕,下面将对 BeanDefinition 的解析过程做详细分析说明。
另外,XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource inputSource, Resource resource) 方法,整体时序图如下:

- 红框部分,就是 BeanDefinition 的解析过程。
参考
摘要: 原创出处 http://cmsblogs.com/?p=2697 「小明哥」,略作修改及补充