配置解析
dubbo 的各个配置项,详细的可以参考官网
只有 group,interface,version 是服务的匹配条件,三者决定是不是同一个服务,其它配置项均为调优和治理参数
所有的配置最终都转为URL,由服务提供方生成,经由注册中心传给消费者
每个配置元素都会有对应的配置类
- dubbo:application 用于配置应用信息,主要是用于服务治理的, 只有其中的compiler和logger用于性能调优, compiler用于配置动态编译器, logger用于配置日志输出方法
- dubbo:registry 用于配置注册中心, 如果有多个注册中心,则使用多个标签声明, 并且在dubbo:service 和dubbo:reference 中 的register属性中指定对应的注册 中心
- dubbo:provider 服务提供者缺省配置,为dubbo:protocol和dubbo:service缺省值配置
- dubbo:service 服务提供者暴露服务配置, 有几个服务要暴露就配置几个
- dubbo:protocol 服务提供者配置,如果需要支持多协议,可以声明多个标签, 并且在dubbo:service中的protocol属性指定使用哪个协议
- dubbo:reference 服务消费者引用服务配置,
- dubbo:consumer 服务消费者缺省值配置, 同时为dubbo:reference的缺省值配置
- dubbo:method 方法 级配置, 为dubbo:service 和dubbo:reference的子标签, 用于控制到方法级
不同粒度的覆盖关系
- 方法级别优先,接口次之, 全局再次之
- 如果级别一样,消费方优先,提供方次之, 其中提供方的配置通过URL,经由注册中心传给消费者
外部化配置
外部化配置 即是将配置放到配置中心,比如如 Apollo, Nacos
外部化配置相对本地配置有更高的优先级, 可以通过 -Ddubbo.config-center.highest-priority=false 调整
dubbo 支持四种配置来源,按配置的优先级从高到低分别是
- JVM参数配置
- 外部化配置
- ServiceConfig、ReferenceConfig 等编程接口采集的配置,比如XML配置等
- 本地配置文件 dubbo.properties
解析服务的实现原理
dubbo 使用spring框架提供的功能,将XML配置文件解析为bean
- spring应用启动时,会调用DefaultBeanDefinitionDocumentReader.parseBeanDefinitions 方法解析xml 标签, 根据每个标签的命名空间决定如何解析该标签
// DefaultBeanDefinitionDocumentReader类
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
// xml 文件的根元素设了默认的命名空间 xmlns = "http://www.springframework.org/schema/beans"
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 {
// <dubbo:xxxx> 会走该分支
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
- BeanDefinitionParserDelegate 会获取该标签的命名空间, NamespaceHandlerResolver根据命名空间返回对应的命名空间处理器. NamespaceHandlerResolver只有一个默认实现 DefaultNamespaceHandlerResolver, 它会去加载 META-INF/spring.handlers 文件
dubbo.jar定义了该文件,内容为
http://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
所以,返回的handler为 DubboNamespaceHandler, 然后用这个handler去解析该标签
// BeanDefinitionParserDelegate类
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = this.getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
} else {
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));
}
}
}
在DubboNamespaceHandler的init 方法会设置每个标签的解析器
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("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig