- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
4.2.2 提取自定义标签处理器
有了命名空间,就可以进行 NamespaceHandler 的提取了,继续之前的 parseCustomElement 函数的跟踪,分析 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver(). resolve(namespaceUri),在 readerContext 初始化的时候其属性 namespaceHandlerResolver 已经被初始化为了 DefaultNamespaceHandlerResolver 的实例,所以,这里调用的 resolve 方法其实调用的是 DefaultNamespaceHandlerResolver 类中的方法。我们进入 DefaultNamespaceHandlerResolver 的 resolve 方法进行查看。
DefaultNamespaceHandlerResolver.java
public NamespaceHandler resolve(String namespaceUri) {
//获取所有已经配置的 handler 映射
Map<String, Object> handlerMappings = getHandlerMappings();
//根据命名空间找到对应的信息
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}else if (handlerOrClassName instanceof NamespaceHandler) {
//已经做过解析的情况,直接从缓存读取
return (NamespaceHandler) handlerOrClassName;
}else {
//没有做过解析,则返回的是类路径
String className = (String) handlerOrClassName;
try {
//使用反射将类路径转化为类
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for
namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler. class.
getName() + "] interface");
}
//初始化类
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.
instantiateClass(handlerClass);
//调用自定义的 NamespaceHandler 的初始化方法
namespaceHandler.init();
//记录在缓存
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}catch (ClassNotFoundException ex) {
throw new FatalBeanException("NamespaceHandler class [" + className +
"] for namespace [" +
namespaceUri + "] not found", ex);
}catch (LinkageError err) {
throw new FatalBeanException("Invalid NamespaceHandler class [" +
className + "] for namespace [" +
namespaceUri + "]: problem with handler class file or dependent
class", err);
}
}
}
上面的函数清晰地阐述了解析自定义 NamespaceHandler 的过程,通过之前的示例程序我们了解到如果要使用自定义标签,那么其中一项必不可少的操作就是在 Spring.handlers 文件中配置命名空间与命名空间处理器的映射关系。只有这样,Spring 才能根据映射关系找到匹配的处理器,而寻找匹配的处理器就是在上面函数中实现的,当获取到自定义的 NamespaceHandler 之后就可以进行处理器初始化并解析了。我们不妨再次回忆一下示例中对于命名空间处理器的内容:
public class MyNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
}
}
当得到自定义命名空间处理后会马上执行 namespaceHandler.init() 来进行自定义 Bean DefinitionParser 的注册。在这里,你可以注册多个标签解析器,当前示例中只有支持<myname:user 的写法,你也可以在这里注册多个解析器,如<myname:A、<myname:B 等,使得 myname 的命名空间中可以支持多种标签解析。
注册后,命名空间处理器就可以根据标签的不同来调用不同的解析器进行解析。那么,根据上面的函数与之前介绍过的例子,我们基本上可以推断 getHandlerMappings 的主要功能就是读取 Spring.handlers 配置文件并将配置文件缓存在 map 中。
private Map<String, Object> getHandlerMappings() {
//如果没有被缓存则开始进行缓存
if (this.handlerMappings == null) {
synchronized (this) {
if (this.handlerMappings == null) {
try {
//this.handlerMappingsLocation 在构造函数中已经被初始化为:META-
INF/Spring.handlers
Properties mappings =
PropertiesLoaderUtils.loadAllProperties (this.
handlerMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded NamespaceHandler mappings: " + mappings);
}
Map<String, Object> handlerMappings = new ConcurrentHashMap<
String, Object>();
//将 Properties 格式文件合并到 Map 格式的 handlerMappings 中
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load NamespaceHandler mappings from
location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return this.handlerMappings;
}
同我们想象的一样,借助了工具类 PropertiesLoaderUtils 对属性 handlerMappingsLocation 进行了配置文件的读取,handlerMappingsLocation 被默认初始化为“META-INF/Spring.handlers”。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论