github新增仓库 "dubbo-read"(点此查看),集合所有《Dubbo原理和源码解析》系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行分享。不定期更新,欢迎Follow。

一、Dubbo 配置方式

Dubbo 支持多种配置方式:

  • XML 配置:基于 Spring 的 Schema 和 XML 扩展机制实现
  • 属性配置:加载 classpath 根目录下的 dubbo.properties
  • API 配置:通过硬编码方式配置(不推荐使用)
  • 注解配置:通过注解方式配置(Dubbo-2.5.7及以上版本支持,不推荐使用)

对于 属性配置 方式,可以通过环境变量、-D 启动参数来指定 dubbo.properties 文件,加载文件顺序为:

    1. -D 启动参数
    2. 环境变量
    3. classpath 根目录

加载代码如下:

public static final String DUBBO_PROPERTIES_KEY = "dubbo.properties.file";
public static final String DEFAULT_DUBBO_PROPERTIES = "dubbo.properties"; private static volatile Properties PROPERTIES; public static Properties getProperties() {
if (PROPERTIES == null) {
synchronized (ConfigUtils.class) {
if (PROPERTIES == null) {
String path = System.getProperty(Constants.DUBBO_PROPERTIES_KEY);
if (path == null || path.length() == 0) {
path = System.getenv(Constants.DUBBO_PROPERTIES_KEY);
if (path == null || path.length() == 0) {
path = Constants.DEFAULT_DUBBO_PROPERTIES;
}
}
PROPERTIES = ConfigUtils.loadProperties(path, false, true);
}
}
}
return PROPERTIES;
}

本文主要分析 XML 配置的实现原理和源码,其他方式不予赘述。

二、XML 配置

文章开头已经提到,XML 配置方式是基于 Spring 的 Schema 和 XML 扩展机制实现的。通过该机制,我们可以编写自己的 Schema,并根据自定义的 Schema 自定义标签来配置 Bean。

使用 Spring 的 XML 扩展机制有以下几个步骤:

    1. 定义 Schema(编写 .xsd 文件)
    2. 定义 JavaBean
    3. 编写 NamespaceHandler 和 BeanDefinitionParser 完成 Schema 解析
    4. 编写 spring.handlers 和 spring.schemas 文件串联解析部件
    5. 在 XML 文件中应用配置
Dubbo 配置相关的代码在 dubbo-config 模块。

2.1 定义 Schema

Schema 的定义体现在 .xsd 文件上,文件位于 dubbo-config-spring 子模块下:

至于 XSD 的数据类型、如何定义,并不是本文的重点,请参考 W3school《Schema 教程》。

2.2 定义 JavaBean

dubbo-config-api 子模块中定义了 Dubbo 所有标签对应的 JavaBean,JavaBean 里面的属性一一对应标签的各配置项。

2.3 解析 Schema

Dubbo 服务框架的 Schema 的解析通过 DubboNamespaceHandler 和 DubboBeanDefinitionParser 实现。

其中,DubboNamespaceHandler 扩展了 Spring 的 NamespaceHandlerSupport,通过重写它的 init() 方法给各个标签注册对应的解析器:

public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
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 DubboBeanDefinitionParser(AnnotationBean.class, true));
}
}

DubboBeanDefinitionParser 实现了 Spring 的 BeanDefinitionParser,通过重写 parse() 方法实现将标签解析为对应的 JavaBean:

public class DubboBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
return parse(element, parserContext, beanClass, required);
} @SuppressWarnings("unchecked")
private static BeanDefinition parse(Element element,ParserContext parserContext,Class<?> beanClass,boolean required) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
//......省略
if (ProtocolConfig.class.equals(beanClass)) {
for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
if (property != null) {
Object value = property.getValue();
if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
}
}
}
} else if (ServiceBean.class.equals(beanClass)) {
String className = element.getAttribute("class");
if(className != null && className.length() > 0) {
RootBeanDefinition classDefinition = new RootBeanDefinition();
classDefinition.setBeanClass(ReflectUtils.forName(className));
classDefinition.setLazyInit(false);
parseProperties(element.getChildNodes(), classDefinition);
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
}
} else if (ProviderConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
} else if (ConsumerConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
}
//......省略
return beanDefinition;
}
}

2.4 串联部件

上面我们已经知道解析的实现类了,那么 Spring 又如何知道该用 DubboNamespaceHandler 来解析 Dubbo 标签呢?这通过编写 spring.handlers 文件实现。

spring.handlers 内容如下:

http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

然后,Spring 通过 spring.schemas 文件得知 Dubbo 标签的 Schema 是 dubbo.xsd,并以此校验应用 XML 配置文件的格式。

spring.schemas 文件内容如下:

http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd

文件位置如下:

2.5 应用配置

通过以上步骤,Dubbo 服务框架就完成了标签解析的功能,用户在应用程序中按照 dubbo.xsd 的格式配置 XML 即可。

Over.

Dubbo原理和源码解析之标签解析的更多相关文章

  1. Dubbo原理和源码解析之服务引用

    一.框架设计 在官方<Dubbo 开发指南>框架设计部分,给出了引用服务时序图: 另外,在官方<Dubbo 用户指南>集群容错部分,给出了服务引用的各功能组件关系图: 本文将根 ...

  2. Dubbo原理和源码解析之服务暴露

    github新增仓库 "dubbo-read"(点此查看),集合所有<Dubbo原理和源码解析>系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行 ...

  3. Dubbo原理和源码解析之“微内核+插件”机制

    github新增仓库 "dubbo-read"(点此查看),集合所有<Dubbo原理和源码解析>系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行 ...

  4. 我是如何在短期内快速掌握Dubbo的原理和源码的(纯干货)?

    写在前面 上周,在[Dubbo系列专题]中更新了两篇文章<冰河开始对Dubbo下手了!>和<俯瞰Dubbo全局,阅读源码前必须掌握这些!!>,收到了很多小伙伴的微信私聊消息,大 ...

  5. [Spark內核] 第41课:Checkpoint彻底解密:Checkpoint的运行原理和源码实现彻底详解

    本课主题 Checkpoint 运行原理图 Checkpoint 源码解析 引言 Checkpoint 到底是什么和需要用 Checkpoint 解决什么问题: Spark 在生产环境下经常会面临 T ...

  6. [Spark内核] 第32课:Spark Worker原理和源码剖析解密:Worker工作流程图、Worker启动Driver源码解密、Worker启动Executor源码解密等

    本課主題 Spark Worker 原理 Worker 启动 Driver 源码鉴赏 Worker 启动 Executor 源码鉴赏 Worker 与 Master 的交互关系 [引言部份:你希望读者 ...

  7. Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析

    相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...

  8. DStream-05 updateStateByKey函数的原理和源码

    Demo updateState 可以到达将每次 word count 计算的结果进行累加. object SocketDstream { def main(args: Array[String]): ...

  9. Kubernetes Job Controller 原理和源码分析(一)

    概述什么是 JobJob 入门示例Job 的 specPod Template并发问题其他属性 概述 Job 是主要的 Kubernetes 原生 Workload 资源之一,是在 Kubernete ...

随机推荐

  1. HttpContext未null处理

    public static HttpContext Current { get { if (instance.Value == null) { instance = new ThreadLocal&l ...

  2. 如何将程序集安装到全局程序集缓存GAC

    针对一些类库项目或用户控件项目(一般来说,这类项目最后编译生成的是一个或多个dll文件),在程序开发完成后,有时需要将开发的程序集(dll文件)安装部署到GAC(全局程序集缓存)中,以便其他的程序也可 ...

  3. 常常搞不清楚SQLServer中的sp_columns来看一看

    The sp_columns catalog stored procedure is equivalent to SQLColumns in ODBC. The results returned ar ...

  4. C++堆栈问题

    编写C++中的两个类 一个只能在栈中分配空间 一个只能在堆中分配. 解答: (1)代码如下 (2)堆栈分配内存的介绍 一.一个经过编译的C/C++的程序占用的内存分成以下几个部分:1.栈区(stack ...

  5. App免费推广途径概要

    说在前面的话:免费其实挺花功夫的,所有的营销的前提是产品和服务是值得推荐的. 1.技术操作维度:ASO,SEO, ASO简单介绍:http://baike.baidu.com/subview/1368 ...

  6. Linq小整理

    Linq(Language Integrated Query)中文翻译为语言集成查询 (1)源起 .net的设计者在类库中定义了一系列的扩展方法 来方便用户操作集合对象 这些扩展方法构成了LINQ的查 ...

  7. C++ 进制转换 十进制十六进制八进制二进制相互转换

    思路: 下面我把相互转换的所有类型都写出来了.实际上都是通过十进制中转的,这样比较简单,写出X进制转成十进制和从十进制转成X进制的两份代码直接拷贝就完成了剩余的部分.哦,对,自己封装了一个charTo ...

  8. RocketMQ源码 — 八、 RocketMQ消息重试

    RocketMQ的消息重试包含了producer发送消息的重试和consumer消息消费的重试. producer发送消息重试 producer在发送消息的时候如果发送失败了,RocketMQ会自动重 ...

  9. Ubuntu 18.04 启动root账号并授权远程登录

    Ubuntu 18.04 刚刚上市2个月,下载安装,尝尝鲜~ 安装界面看上去舒服许多, 安装的速度也较之前17.04 和16.04 都快了许多.抱歉,未截图. Ubuntu 安装完成后默认不启动roo ...

  10. Spring Cloud Config - RSA简介以及使用RSA加密配置文件

    简介 RSA非对称加密有着非常强大的安全性,HTTPS的SSL加密就是使用这种方法进行HTTPS请求加密传输的.因为RSA算法会涉及Private Key和Public Key分别用来加密和解密,所以 ...