上文,对 parse() 应该是有印象的。
没错,在前一小结的第五点我们介绍了 DubboBeanDefinitionParser 类。该类有个方法就叫 parse()。那么这个 parse() 方法有什么用? Spring 是如何感知到我就要调用 DubboBeanDefinitionParser 类中的 parse() 方法的呢?我们带着这两个问题接着往下看。
BeanDefinitionParserDelegate
上面图的流程比较长,我们先着重看下 BeanDefinitionParserDelegate 类中的几个关键方法。
BeanDefinitionParserDelegate.java
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
// 获取当前 element 的 namespaceURI
// 比如 dubbo.xsd 中的为 http://dubbo.apache.org/schema/dubbo
String namespaceUri = this.getNamespaceURI(ele);
// 根据 URI 获取对应的 NamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
} else {
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
这个方法干了三件事
- 获取 element 元素的 namespaceURI,并据此获取对应的 NamespaceHandler 对象。Dubbo 自定义标签(比如 Dubbo:provider) namespaceUri 的值为
http://dubbo.apache.org/schema/dubbo
;
- 根据 step1 获取到的 namespaceUri ,获取对应的 NamespaceHandler 对象。这里会调用 DefaultNamespaceHandlerResolver 类的 resolve() 方法,我们下面会分析;
- 调用 handler 的 parse 方法,我们自定以的 handler 会继承 NamespaceHandlerSupport 类,所以这里调用的其实是 NamespaceHandlerSupport 类的 parse() 方法,后文分析;
一图胜千言
在详细分析 step2 和 step3 中涉及的 resolver() 和 parse() 方法前,先放一张时序图让大家有个基本概念:
DefaultNamespaceHandlerResolver.java
public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = this.getHandlerMappings();
// 以 namespaceUri 为 Key 获取对应的 handlerOrClassName
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
} else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler)handlerOrClassName;
} else {
// 如果不为空且不为 NamespaceHandler 的实例,转换为 String 类型
// DubboNamespaceHandler 执行的便是这段逻辑
String className = (String)handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
// handlerClass 是否为 NamespaceHandler 的实现类,若不是则抛出异常
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
} else {
// 初始化 handlerClass
NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);
// 执行 handlerClass类的 init() 方法
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
} catch (ClassNotFoundException var7) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
} catch (LinkageError var8) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
}
}
}
resolve() 方法用途是根据方法参数中的 namespaceUri 获取对应的 NamespaceHandler 对象。这里会先尝试以 namespaceUri 为 key 去 handlerMappings 集合中取对象。
如果 handlerOrClassName 不为 null 且不为 NamespaceHandler 的实例。那么尝试将 handlerOrClassN