《Spring 知识面面通 之 自定义NamespaceHandler详解》博文中对自定义NamespaceHandler
进行演示,本文会对NamespaceHandler
的加载过程进行解析。
NamespaceHandler
加载过程流程
流程图中罗列了Spring加载配置的整个过程,其中,从BeanDefinitionParserDelegate.parseCustomElement(...)
开始,即开始了对命名空间NamespaceHandler
的解析,本文对这部分内容进行解析。
NamespaceHandler
加载过程解析
1) BeanDefinitionParserDelegate.parseCustomElement(…)方法。
① 取得指定元素的命名空间。
② 通过DefaultNamespaceHandlerResolver
解析指定元素命名空间对应的NamespaceHandler
。
③ 通过查找的NamespaceHandler
解析指定元素,取得Bean
定义实例。
/**
* 解析自定义元素.
* @param ele 元素.
* @param containingBd Bean定义.
* @return 解析Bean定义.
*/
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获取元素命名空间.
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 解析元素命名空间对应的NamespaceHandler.
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 解析当前元素.
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
2) DefaultNamespaceHandlerResolver.resolve(…)方法。
① 加载所有依赖的META-INF/spring.handlers
文件,取得命名空间对应处理器映射。
② 根据命名空间从①
的映射中查找对应的NamespaceHandler
类。
③ 映射配置的NamespaceHandler
类必须实现NamespaceHandler
接口,否则抛出异常。
④ 根据配置映射的NamespaceHandler
类路径进行实例化。
⑤ 调用NamespaceHandler
的init()
方法,指定命名空间元素对应的解析器。
/**
* 从配置映射中查找所提供命名空间URI的NamespaceHandler.
* @param namespaceUri 相关命名空间URI.
* @return NamespaceHandler,若未找到,则为null.
*/
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
// 加载处理器映射.
Map<String, Object> handlerMappings = getHandlerMappings();
// 根据namespaceUri查找处理器类路径.
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);
// 处理器需实现NamespaceHandler接口.
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("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
3) DefaultNamespaceHandlerResolver.getHandlerMappings()方法。
① 加载所有依赖的META-INF/spring.handlers
文件,取得命名空间对应处理器映射,存储在Properties
实例中。
② 将数据由Properties
转存到Map
中。
/**
* 延迟加载指定的NamespaceHandler映射.
*/
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
synchronized (this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
try {
// 搜索META-INF/spring.handlers文件.
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded NamespaceHandler mappings: " + mappings);
}
Map<String, Object> mappingsToUse = new ConcurrentHashMap<>(mappings.size());
// 将Properties数据转换到Map中.
CollectionUtils.mergePropertiesIntoMap(mappings, mappingsToUse);
handlerMappings = mappingsToUse;
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return handlerMappings;
}
4) NamespaceHandlerSupport.parse(…)方法。
① 使用提供元素的本地名称查找BeanDefinitionParser
。
② 调用BeanDefinitionParser
实现进行解析。
/**
* 通过委托给为Element注册的BeanDefinitionParser来解析提供的Element.
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 使用提供元素的本地名称查找BeanDefinitionParser.
BeanDefinitionParser parser = findParserForElement(element, parserContext);
// 调用BeanDefinitionParser实现进行解析.
return (parser != null ? parser.parse(element, parserContext) : null);
}
5) NamespaceHandlerSupport.findParserForElement(…)方法。
① 通过指定元素,取得元素的本地参数名称。
② 根据本地名称查找已注册的BeanDefinitionParser
。
/**
* 使用提供的元素的本地名称查找BeanDefinitionParser.
*/
@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
// 获取提供元素的本地名称.
String localName = parserContext.getDelegate().getLocalName(element);
// 根据本地名称查找BeanDefinitionParser.
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
6) BeanDefinitionParser.parse(…)方法。
BeanDefinitionParser.parse(...)
是由具体开发进行编写的,其中涉及元素解析、元素校验、注册对应Beam
。
总结
‘工欲善其事必先利其器’,只有当对原理的了解达到一定程度,才能在实际遇到问题,简洁、快速、高效的解决问题。
源码解析基于spring-framework-5.0.5.RELEASE
版本源码。
若文中存在错误和不足,欢迎指正!