dubbo系列之xml解析原理NamespaceHandler(二)
前言
上一节中我们基于springboot搭建了dubbo的基本用例,能够使用dubbo的基本功能,在dubbo重新开源之前,大部分人都是通过spring的xml文件进行配置的,基于这个背景,有必要讲一下dubbo是怎么解析xml文件,生成代理对象的。
版本说明
springboot starter : 0.1.1
dubbo版本: 2.6.2
DubboNamespaceHandler
这个是dubbo基于spring的扩展点用来解析xml文件的类
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
@Override
public void init() {
// 解析<dubbo:application/>标签 全局配置,用于配置当前应用信息,不管该应用是提供者还是消费者
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
// 解析<dubbo:module/>标签 模块配置 , 用于配置当前模块信息
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
// 解析<dubbo:registry/>标签 用于配置连接注册中心相关信息
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
// 解析<dubbo:monitor/>标签 用于配置连接监控中心相关信息
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
// 解析<dubbo:provider/>标签 当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
// 解析<dubbo:consumer/>标签 当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
// 解析<dubbo:protocol/>标签 协议
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
// 解析<dubbo:service/>标签 用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
// 解析<dubbo:reference/> 标签 用于创建一个远程服务代理,一个引用可以指向多个注册中心
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
// 解析<dubbo:annotation/>标签
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
}
spring解析
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if(delegate.isDefaultNamespace(root)) {//是否是默认的NameSpace,Dubbo Namespace不是默认的
NodeList nl = root.getChildNodes();
for(int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if(node instanceof Element) {
Element ele = (Element)node;
if(delegate.isDefaultNamespace(ele)) {
this.parseDefaultElement(ele, delegate);
} else {
delegate.parseCustomElement(ele);
}
}
}
} else {
//通过代理来解析Dubbo配置文件中 Element 元素
delegate.parseCustomElement(root);
}
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
//通过元素获取namespaceURI
String namespaceUri = this.getNamespaceURI(ele);
//如 ele:name 为 dubbo:application ,则namespaceUri = http://code.alibabatech.com/schema/dubbo
//通过NameSpaceURi 获取NamespaceHandler ,Dubbo对应的是DubboNameSpaceHandler
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 {
//DubboBeanDefinitionParser的parse解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
NamespaceHandlerSupport
spring的自定义schema标签解析是通过写一个继承自NamespaceHandlerSupport的类,并实现init方法,在init方法中,去注册解析器,然后在解析xml的是,通过约定的key去map中拿到相应的解析去解析。
registerBeanDefinitionParser是一个map
spring容器在启动的时候,遇到自定义标签的时候,会通过标签名称去registerBeanDefinitionParser中寻找标签解析器,然后调用标签解析器中的parse方法,得到BeanDefinition,最后实例化bean.
所以dubbo的xml解析原理就是这样的,基于spring的NamespaceHandler的机制,然后通过标签对应的解析器进行解析,最后实例化bean