spring-core IoC 之解析 标签:解析自定义标签
前面四篇文章都是分析 Bean 默认标签的解析过程,包括 基本属性、六个子元素(meta、lookup-method、replaced-method、constructor-arg、property、qualifier),涉及内容较多,拆分成了四篇文章,导致我们已经忘记从哪里出发的了。所以,我们先来回顾下。
DefaultBeanDefinitionDocumentReader 的 #processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法,负责 标签的解析:
- 在解析过程中,首先调用 BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele) 方法,完成默认标签的解析。
- 如果解析成功(返回的 bdHolder != null ),则调用 BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) 方法,完成自定义标签元素的解析。
1. decorateBeanDefinitionIfRequired
前面四篇文章已经分析了默认标签的解析,所以这篇文章分析自定义标签的解析。代码如下:
// BeanDefinitionParserDelegate.java
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// <1> 获取自定义标签的命名空间
String namespaceUri = getNamespaceURI(node);
// <2> 过滤掉默认命名标签
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
// <2> 获取相应的处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
// <3> 进行装饰处理
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
} else if (namespaceUri.startsWith("http://www.springframework.org/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
} else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
2. decorateIfRequired
// BeanDefinitionParserDelegate.java
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// <1> 获取自定义标签的命名空间
String namespaceUri = getNamespaceURI(node);
// <2> 过滤掉默认命名标签
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
// <2> 获取相应的处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
// <3> 进行装饰处理
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
} else if (namespaceUri.startsWith("http://www.springframework.org/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
} else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
3. 小结
至此,BeanDefinition 的解析过程已经全部完成了,下面做一个简要的总结:
解析 BeanDefinition 的入口在 DefaultBeanDefinitionDocumentReader 的#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法。该方法会根据命令空间来判断标签是默认标签还是自定义标签,其中:
- 默认标签,由 #parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 方法来实现
- 自定义标签,由 BeanDefinitionParserDelegate 的 #parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) 方法来实现。
在默认标签解析中,会根据标签名称的不同进行 import、alias、bean、beans 四大标签进行处理。其中 bean 标签的解析为核心,它由 processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法实现。
processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法,开始进入解析核心工作,分为三步:
- 解析默认标签的默认标签:BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele, …) 方法。该方法会依次解析 标签的属性、各个子元素,解析完成后返回一个 GenericBeanDefinition 实例对象。
- 解析默认标签下的自定义标签:BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) 方法。
- 注册解析的 BeanDefinition:BeanDefinitionReaderUtils#registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 方法。