- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
4.2.3 标签解析
得到了解析器以及要分析的元素后,Spring 就可以将解析工作委托给自定义解析器去解析了。在 Spring 中的代码为:
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))
以之前提到的示例进行分析,此时的 handler 已经被实例化成为了我们自定义的 MyNamespaceHandler 了,而 MyNamespaceHandler 也已经完成了初始化的工作,但是在我们实现的自定义命名空间处理器中并没有实现 parse 方法,所以推断,这个方法是父类中的实现,查看父类 NamespaceHandlerSupport 中的 parse 方法。
NamespaceHandlerSupport.java
public BeanDefinition parse(Element element, ParserContext parserContext) {
//寻找解析器并进行解析操作
returnfindParserForElement(element, parserContext).parse(element, parserContext);
}
解析过程中首先是寻找元素对应的解析器,进而调用解析器中的 parse 方法,那么结合示例来讲,其实就是首先获取在 MyNameSpaceHandler 类中的 init 方法中注册的对应的 UserBean DefinitionParser 实例,并调用其 parse 方法进行进一步解析。
private BeanDefinitionParser findParserForElement(Element element, ParserContext parser
Context) {
//获取元素名称,也就是<myname:user 中的 user,若在示例中,此时 localName 为 user
String localName = parserContext.getDelegate().getLocalName(element);
//根据 user 找到对应的解析器,也就是在
//registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
//注册的解析器
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName +
"]", element);
}
return parser;
}
而对于 parse 方法的处理:
public final BeanDefinition parse(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error(
"Id is required for element '" + parserContext.
getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = new String[0];
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases =
StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
//将 AbstractBeanDefinition 转换为 BeanDefinitionHolder 并注册
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id,
aliases);
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
//需要通知监听器则进行处理
BeanComponentDefinition componentDefinition = new BeanComponent
Definition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}
catch (BeanDefinitionStoreException ex) {
parserContext.getReaderContext().error(ex.getMessage(), element);
return null;
}
}
return definition;
}
虽说是对自定义配置文件的解析,但是,我们可以看到,在这个函数中大部分的代码是用来处理将解析后的 AbstractBeanDefinition 转化为 BeanDefinitionHolder 并注册的功能,而真正去做解析的事情委托给了函数 parseInternal,正是这句代码调用了我们自定义的解析函数。
在 parseInternal 中并不是直接调用自定义的 doParse 函数,而是进行了一系列的数据准备,包括对 beanClass、scope、lazyInit 等属性的准备。
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext
parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
//获取自定义标签中的 class,此时会调用自定义解析器如 UserBeanDefinitionParser 中的 getBeanClass
方法。
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
//若子类没有重写 getBeanClass 方法则尝试检查子类是否重写 getBeanClassName 方法
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
if (parserContext.isNested()) {
//若存在父类则使用父类的 scope 属性
builder.setScope(parserContext.getContainingBeanDefinition().getScope());
}
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
//配置延迟加载
builder.setLazyInit(true);
}
//调用子类重写的 doParse 方法进行解析
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
protected void doParse(Element element, ParserContext parserContext, BeanDefinition
Builder builder) {
doParse(element, builder);
}
回顾一下全部的自定义标签处理过程,虽然在实例中我们定义 UserBeanDefinitionParser,但是在其中我们只是做了与自己业务逻辑相关的部分。不过我们没做但是并不代表没有,在这个处理过程中同样也是按照 Spring 中默认标签的处理方式进行,包括创建 BeanDefinition 以及进行相应默认属性的设置,对于这些工作 Spring 都默默地帮我们实现了,只是暴露出一些接口来供用户实现个性化的业务。通过对本章的了解,相信读者对 Spring 中自定义标签的使用以及在解析自定义标签过程中 Spring 为我们做了哪些工作会有一个全面的了解。到此为止我们已经完成了 Spring 中全部的解析工作,也就是说到现在为止我们已经理解了 Spring 将 bean 从配置文件到加载到内存中的全过程,而接下来的任务便是如何使用这些 bean,下一章将介绍 bean 的加载。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论