IOC-注册BeanDefinitions
本文主要基于 Spring 5.0.6.RELEASE
摘要: 原创出处 http://cmsblogs.com/?p=2697 「小明哥」,谢谢!
获取 XML Document 对象后,会根据该对象和 Resource 资源对象调用 XmlBeanDefinitionReader#registerBeanDefinitions(Document doc, Resource resource) 方法,开始注册 BeanDefinitions 之旅。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// AbstractBeanDefinitionReader.java
private
final
BeanDefinitionRegistry registry; // XmlBeanDefinitionReader.java
public
int registerBeanDefinitions(Document
doc,
Resource resource) throws BeanDefinitionStoreException {
// <1> 创建 BeanDefinitionDocumentReader 对象 BeanDefinitionDocumentReader
documentReader = createBeanDefinitionDocumentReader(); // <2> 获取已注册的 BeanDefinition 数量
int
countBefore =
getRegistry().getBeanDefinitionCount(); // <3> 创建 XmlReaderContext 对象 // <4> 注册 BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // 计算新注册的
BeanDefinition 数量 return getRegistry().getBeanDefinitionCount() - countBefore;
}
- <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 数量。
1. createBeanDefinitionDocumentReader
#createBeanDefinitionDocumentReader(),实例化 BeanDefinitionDocumentReader 对象。代码如下:
1
2
3
4
5
6
7
8
/** * documentReader 的类 * * @see #createBeanDefinitionDocumentReader()
*/
private Class<? extends BeanDefinitionDocumentReader> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanUtils.instantiateClass(this.documentReaderClass);
}
- documentReaderClass 的默认值为 DefaultBeanDefinitionDocumentReader.class 。关于它,我们在后续的文章,详细解析。
2. registerBeanDefinitions
BeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext) 方法,注册 BeanDefinition ,在接口 BeanDefinitionDocumentReader 中定义。代码如下:
1
2
3
4
5
6
7
8
public interface BeanDefinitionDocumentReader {
/** * Read bean definitions from the given DOM document and
* register them with the registry in the given reader context. * @param doc the DOM document
* @param readerContext the current context of the reader
* (includes the target registry and the resource being parsed) * @throws BeanDefinitionStoreException in case of parsing errors
*/
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException;
}
从给定的 Document 对象中解析定义的 BeanDefinition 并将他们注册到注册表中。方法接收两个参数:
- doc 方法参数:待解析的 Document 对象。
- readerContext「3. createReaderContext」 方法,解析器的当前上下文,包括目标注册表和被解析的资源。它是根据 Resource 来创建的,见 。
2.1 DefaultBeanDefinitionDocumentReader
BeanDefinitionDocumentReader 有且只有一个默认实现类 DefaultBeanDefinitionDocumentReader 。它对 #registerBeanDefinitions(…) 方法的实现代码如下:
DefaultBeanDefinitionDocumentReader 对该方法提供了实现:
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
@Nullable
private XmlReaderContext readerContext;
@Nullable
private BeanDefinitionParserDelegate delegate;
/** * This implementation parses bean definitions according to the "spring-beans" XSD
* (or DTD, historically). * <p>Opens a DOM Document;
then initializes the default settings
* specified at the {
@code <beans/>
}
level;
then parses the contained bean definitions. */
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext; // 获得 XML
Document Root Element // 执行注册
BeanDefinition doRegisterBeanDefinitions(doc.getDocumentElement());
}
/** * Register each bean definition within the given root {
@code <beans/>
}
element. */
@SuppressWarnings("deprecation") //
for
Environment.acceptsProfiles(String...)protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in
this method. In// order to propagate and preserve <beans>
default-* attributes correctly,// keep track of the current (parent) delegate, which may be
null. Create// the
new (child) delegate with a reference to the parent for fallback purposes,// then ultimately reset this.delegate back to its original (parent) reference.// this behavior emulates a stack of delegates without actually necessitating one.// 记录老的 BeanDefinitionParserDelegate 对象BeanDefinitionParserDelegate parent =
this.delegate; // <1> 创建
BeanDefinitionParserDelegate 对象,并进行设置到 delegatethis.delegate = createDelegate(getReaderContext(), root, parent);
// <2> 检查 <beans /> 根标签的命名空间是否为空,或者是 http://www.springframework.org/schema/beansif (this.delegate.isDefaultNamespace(root)) { // <2.1> 处理 profile 属性。可参见《Spring3自定义环境配置 <beans profile="">》http://nassir.iteye.com/blog/1535799 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) { // <2.2> 使用分隔符切分,可能有多个 profile 。 String[]
specifiedProfiles =
StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); // <2.3> 如果所有 profile 都无效,则不进行注册 // We cannot use Profiles.of(...) since profile expressions are not supported // in XML config. See SPR-12458
for details. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to
specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); }
return;
}
}
} // <3> 解析前处理preProcessXml(root);// <4> 解析parseBeanDefinitions(root,
this.delegate);
// <5> 解析后处理postProcessXml(root);
// 设置 delegate 回老的
BeanDefinitionParserDelegate 对象this.delegate = parent;
}
- <1>解析 BeanDefinition 处,创建 BeanDefinitionParserDelegate 对象,并进行设置到 delegate 。BeanDefinitionParserDelegate 是一个重要的类,它负责 。代码如下: FROM 《Spring 源码深度解析》P16 定义解析 XML Element 的各种方法
1
2
3
4
5
6
7
8
9
protected BeanDefinitionParserDelegate createDelegate( XmlReaderContext readerContext, Element root, @Nullable
BeanDefinitionParserDelegate parentDelegate) {
// 创建 BeanDefinitionParserDelegate 对象 BeanDefinitionParserDelegate delegate =
new
BeanDefinitionParserDelegate(readerContext);
// 初始化默认 delegate.initDefaults(root, parentDelegate);
return delegate;
}
- <2>根http://www.springframework.org/schema/beans 处,检查 标签的命名空间是否为空,或者是 。
- <2.1>《《Spring3自定义环境配置 》》 处,判断是否 上配置了 profile 属性。不了解这块的胖友,可以看下 。
- <2.2>多个 处,使用分隔符切分,可能有 profile 。
- <2.3> 处,判断,如果所有 profile 都无效,则 return 不进行注册。
- <4>「3.1 parseBeanDefinitions」 处,调用 #parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法,进行解析逻辑。详细解析,见 。
- <3>前后 / <5> 处,解析 的处理,目前这两个方法都是空实现,交由子类来实现。代码如下:
1
2
3
4
5
6
protected void preProcessXml(Element root) {
}
protected void postProcessXml(Element root) {
}
2.1.1 parseBeanDefinitions
#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法,进行解析逻辑。代码如下:
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
/** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// <1> 如果根节点使用默认命名空间,执行默认解析
if (delegate.isDefaultNamespace(root)) {
// 遍历子节点
NodeList nl = root.getChildNodes();
for (int i = 0;
i < nl.getLength();
i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node; // <1> 如果该节点使用默认命名空间,执行默认解析
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate); // 如果该节点非默认命名空间,执行自定义解析 }
else {
delegate.parseCustomElement(ele);
}
}
} // <2> 如果根节点非默认命名空间,执行自定义解析 }
else {
delegate.parseCustomElement(root);
}
}
- Spring 有两种 Bean 声明方式:
- 配置文件式声明: 。对应 <1> 处。
- 自定义注解方式: 。对应 <2> 处。
- <1>根子使用 处,如果 节点或 节点 默认命名空间,调用 #parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 方法,执行默认解析。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private 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);
}
}
```plain text
- 详细的解析,见后续文章。
```
- <2>根子不使用自定义 处,如果 节点或 节点 默认命名空间,调用 BeanDefinitionParserDelegate#parseCustomElement(Element ele) 方法,执行 解析。详细的解析,见后续文章。
3. createReaderContext
#createReaderContext(Resource resource) 方法,创建 XmlReaderContext 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private ProblemReporter problemReporter = new FailFastProblemReporter();
private ReaderEventListener eventListener = new EmptyReaderEventListener();
private SourceExtractor sourceExtractor = new NullSourceExtractor();
@Nullable
private NamespaceHandlerResolver namespaceHandlerResolver;
/** * Create the {
@link XmlReaderContext
}
to pass over to the document reader. */
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, getNamespaceHandlerResolver());
}
关于 XmlReaderContext 的详细解析,见后续文章。
4. 小结
至此,XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource inputSource, Resource resource) 方法中,做的三件事情已经全部分析完毕,下面将对 BeanDefinition 的解析过程做详细分析说明。
另外,XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource inputSource, Resource resource) 方法,整体时序图如下:
时序图
- 红框部分,就是 BeanDefinition 的解析过程 。