Spring之默认标签的解析(八) bean标签的解析及注册(7)—— 默认标签中的自定义标签元素
根据代码的进度,前几篇中我们已经了解默认表情的解析以及提取,接下来我们要进行默认标签中的自定义标签。因为时间也挺久,我们回到入口方法,回顾一下原来的过程:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
我们用很长一段时间都在分析 **delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);**这句代码。接下来,我们要进行 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 的分析。
有一种场景,比如
<bean id="test" class="test.MyClass">
<myBean:user username="tom"/>
<bean>
当Spring中的bean使用的是默认的标签配置,但是其中的子元素却使用来自定义的配置时,这句代码便会起作用了。 这里有一个疑问,我们之前了解,对 bean的解析分为两种类型,一种是默认类型的解析,另 一种是自定义类型的解析 ,这不正是自定义类型的解析吗? 为什么会在默认类型解析中单独添加一个方法处理呢?确实,这个问题很让人迷惑,但是,这个自定义类型并不是以 Bean 的形式出现的呢?我们之前讲过的两种类型的不 同处理只是针对 Bean 的,这里我们看到,这个自定义类型其实是属性 。 好了,我们继续分析下这段代码的逻辑:
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}
这里将函数中第三个参数设置为空,那么第三个参数是做什么用的呢?什么情况下不为空 呢?其实这第三个参数是父类 bean,当对某个嵌套配置进行分析时,这里需要传递父类 beanDefinition。 分析源码得知这里传递的参数其实是为了使用父类的 scope属性,以备子类若 没有设置scope时默认使用父类的属性,这里分析的是顶层配置, 所以传递null。 将第三个参
数设置为空后进一步跟踪函数:
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = originalDef;
// Decorate based on custom attributes first.
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// Decorate based on custom nested elements.
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
上面 的代码,我们看到函数分别对元素的所有属性以及子节点进行了 decorateIfRequired函数的调用,我们继续跟踪代码:
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(node);
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
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/schema/")) {
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;
}
我们来简单看一下思路,首先就是获取们属性或者元素的命名空间,以此来来判断该元素或者属性是否适用于自定义标签的解析条件, 找出自定义类型所对应的 NamespaceHandler并进行进一步解析。 【具体解析过程暂时掠过…】。
我们总结下 decorateBeanDefinitionlfR.equired 方法的作用 ,在decorateBeanDefinitionlfRequired 中我们可以看到对于程序默认的标签的处理其实是直接略过的 ,因为默认的标签到这里已经被处理完了,这里只对自定义的标签或者说对 bean 的自定义属性感兴趣。 在方法中实现了寻找自定义标签并根据自定义标签寻找命名空间处理器, 并进行进一步的解析。