调用 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 的实例。那么尝试将 handlerOrClassName 作为 className 并调用 BeanUtils.instantiateClass() 方法初始化一个
NamespaceHandler 实例。初始化后,调用其 init() 方法。这个 init() 方法比较重要,我们接着往下看。
DubboNamespaceHandler
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
NamespaceHandlerSupport
private final Map<String, BeanDefinitionParser> parsers = new HashMap();
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}
DubboNamespaceHandler 类中的 init() 方法干的事情特别简单,就是新建 DubboBeanDefinitionParser 对象并将其放入 NamespaceHandlerSupport 类的 parsers 集合中。我们再回顾一下 parseCustomElement() 方法。
BeanDefinitionParserDelegate.java
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
// 省略...
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
// 省略...
}
这里会调用 NamespaceHandlerSupport 类的 parse() 方法。我们继续跟踪一下。
public BeanDefinition parse(Element element, ParserContext parserContext) {
return this.findParserForElement(element, parserContext).parse(element, parserContext);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element);
BeanDefinitionParser parser = (BeanDefinitionParser)this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}