- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
3.1.3 解析默认标签中的自定义标签元素
到这里我们已经完成了分析默认标签的解析与提取过程,或许涉及的内容太多,我们已经忘了我们从哪个函数开始的了,我们再次回顾下默认标签解析函数的起始函数:
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, getReader
Context().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));
}
}
我们已经用了大量的篇幅分析了 BeanDefinitionHolder bdHolder = delegate.parseBean DefinitionElement(ele) 这句代码,接下来,我们要进行 bdHolder = delegate.decorateBean DefinitionIfRequired(ele, bdHolder) 代码的分析,首先大致了解下这句代码的作用,其实我们可以从语义上分析:如果需要的话就对 beanDefinition 进行装饰,那这句代码到底是什么功能呢?其实这句代码适用于这样的场景,如:
<bean id="test" class="test.MyClass">
<mybean:user username="aaa"/>
</bean>
当 Spring 中的 bean 使用的是默认的标签配置,但是其中的子元素却使用了自定义的配置时,这句代码便会起作用了。可能有人会有疑问,之前讲过,对 bean 的解析分为两种类型,一种是默认类型的解析,另一种是自定义类型的解析,这不正是自定义类型的解析吗?为什么会在默认类型解析中单独添加一个方法处理呢?确实,这个问题很让人迷惑,但是,不知道聪明的读者是否有发现,这个自定义类型并不是以 Bean 的形式出现的呢?我们之前讲过的两种类型的不同处理只是针对 Bean 的,这里我们看到,这个自定义类型其实是属性。好了,我们继续分析下这段代码的逻辑。
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder
definitionHolder) {
return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}
这里将函数中第三个参数设置为空,那么第三个参数是做什么用的呢?什么情况下不为空呢?其实这第三个参数是父类 bean ,当对某个嵌套配置进行分析时,这里需要传递父类 beanDefinition。分析源码得知这里传递的参数其实是为了使用父类的 scope 属性,以备子类若没有设置 scope 时默认使用父类的属性,这里分析的是顶层配置,所以传递 null。将第三个参数设置为空后进一步跟踪函数:
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = definitionHolder;
NamedNodeMap attributes = ele.getAttributes();
//遍历所有的属性,看看是否有适用于修饰的属性
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition =decorateIfRequired(node, finalDefinition, containingBd);
}
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 函数的调用,我们继续跟踪代码:
private BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {
//获取自定义标签的命名空间
String namespaceUri = getNamespaceURI(node);
//对于非默认标签进行修饰
if (!isDefaultNamespace(namespaceUri)) {
//根据命名空间找到对应的处理器
NamespaceHandler handler = this.readerContext. getNamespaceHandler Resolver().
resolve(namespaceUri);
if (handler != null) {
//进行修饰
return handler.decorate(node, originalDef, new ParserContext(this.readerContext,
this, containingBd));
}
else if (namespaceUri != null && 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;
}
public String getNamespaceURI(Node node) {
return node.getNamespaceURI();
}
public boolean isDefaultNamespace(String namespaceUri) {
//BEANS_NAMESPACE_URI = "http://www.Springframework.org/schema/beans";
return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals
(namespaceUri));
}
程序走到这里,条理其实已经非常清楚了,首先获取属性或者元素的命名空间,以此来判断该元素或者属性是否适用于自定义标签的解析条件,找出自定义类型所对应的 NamespaceHandler 并进行进一步解析。在自定义标签解析的章节我们会重点讲解,这里暂时先略过。
我们总结下 decorateBeanDefinitionIfRequired 方法的作用,在 decorateBeanDefinitionIfRequired 中我们可以看到对于程序默认的标签的处理其实是直接略过的,因为默认的标签到这里已经被处理完了,这里只对自定义的标签或者说对 bean 的自定义属性感兴趣。在方法中实现了寻找自定义标签并根据自定义标签寻找命名空间处理器,并进行进一步的解析。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论