Dubbo学习-源码学习
Dubbo概述
dubbo框架提供多协议远程调用,服务提供方可以是分布式部署。dubbo框架可以很简单的帮我们实现微服务。
此处援引官网上图片

dubbo分为客户端和服务提供方
服务方将服务注册到注册中心
客户端从注册中心获取已注册服务访问方式
客户端通过指定协议访问服务提供方
根据dubbo架构,源码分析我们主要切入点是:
- dubbo配置如何生效
- 客户端如何调用服务
- 注册的服务如何保证被调用到
- dubbo远程调用的协议如何工作
针对以上我们来分析Dubbo源码:
Dubbo源码是maven管理,工程主要由dubbo-config,dubbo-container,dubbo-filter,dubbo-monitor,dubbo-registry,dubbo-remoting,dubbo-rpc,dubbo-serialization组成。

- dubbo-config :dubbo配置文件相关模块
- dubbo-container :dubbo依赖的上下文
- dubbo-filter : dubbo支持的请求过滤器
- dubbo-monitor : dubbo监控管理模块
- dubbo-registry : dubbo使用注册中心相关的模块
- dubbo-remoting : dubbo整个远程交互框架,如何将通道、序列化、通信载体有机整合
- dubbo-rpc : dubbo远程调用协议实现。
- dubbo-serialization : 远程通信中序列化实现
dubbo配置加载
dubbo配置是以松耦合的方式嵌入到spring里面,因此说到dubbo配置加载就必然和spring扯不开关系。
从dubbo配置文件的命名空间说起,我们通常在配置dubbo服务时要在spring配置基础上添加dubbo的命名空间(xmlns)和模板:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
xmlns:dubbo的值指定了dubbo配置命名空间。
spring中不同的命名空间对应不同的配置解析器,那么dubbo的命名空间http://code.alibabatech.com/schema/dubbo也就对应着自己的解析器。
spring维护着命名空间和对应解析器的关系,这些对应关系包括spring内置的和第三方定制关系
spring命名空间
spring启动中解析dubbo xml文件时首先获取跟节点中的所有xmlns值,根据配置的命名空间从命名空间管理器中获取该空间对应的解析器对象
命名空间管理器会从classpath下META-INF/下加载并解析所有的所有spring.handlers命名的文件,该文件以键值对配置了命名空间和对应解析器。
dubbo的命名spring.handler配置如下:
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
路径:META-INF/dubbo/spring.handler
如此,spring在加载dubbo配置时会调用dubbo命名空间解析器DubboNamespaceHandler来解析配置文件,dubbo的入口也就是DubboNamespaceHandler。
dubbo配置解析处理器(DubboNamespaceHandler)
dubbo配置解析处理器就是命名空间配置的com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler,该处理器作为dubbo对spring的扩展完成dubbo自定义的配置解析工作。spring的命名空间处理器扩展点是:org.springframework.beans.factory.xml.NamespaceHandlerSupport,DubboNamespaceHandler完成dubbo内部所有解析器初始和加载。解析器包括application节点解析、module节点解析、registry、monitor、provider、consumer、protocol、service、reference、annotation。

这些解析器初始化代码如下:
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));
}
DubboNamespaceHandler做了什么
spring加载配置文件过程中,读取到一个xml节点时,会将节点信息传递给DubboNamespaceHandler,handler获取节点的LocalName(在一个命名空间下去掉前缀剩下的节点名 称),根据名称从DubboNamespaceHandler获取对应的Parser,如:LocalName是application,就会获取到Handler初始化时注册的application对应的 DubboBeanDefinitionParser对象,并调用该解析器的parse方法将节点转换成spring的RootBeanDefinition对象,对象保存了创建一个bean对象所需的所有信 息。
Dubbo服务(ServiceBean)
通过registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));注册的DubboBeanDefinitionParser
创建出的RootBeanDefinition最终被spring实例化成ServiceBean,ServiceBean即Dubbo实际的服务实例。实例化结束后,ServiceBean会从spring容器中获取配置的Provider信 息、application、module、registry、monitor、protocol等配置信息并设置到ServiceBean,设置完成后将服务自身暴露出去,如果本次暴露失败或者没有暴露,则在spring容器启 动完成后会再进行一次暴露。
服务暴露
服务暴露通过调用ServiceBean的export方法,通过注册中心,最终将服务实例以指定的协议暴露给调用方。
准备暴露路径
服务暴露前需要组织自己的访问路径和协议信息,只有有了这些信息,才能确定以何种协议被访问,以及通过什么路径被访问。组织访问信息的方法是服务自身的doExportUrls
ServiceConfig.doExportUrls()
private void doExportUrls() {
List<URL> registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols) {
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
该方法调用了doExportUrlsFor1Protocol方法将协议和注册路径具体的组装起来,形成dubbo的访问路径,将访问路径包装成可被远程调用的调用器invoker。
invoker的生成代码如下:
//如果配置不是local则暴露为远程服务.(配置为local,则表示只暴露本地服务)
if (! Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope) ){
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
if (registryURLs != null && registryURLs.size() > 0
&& url.getParameter("register", true)) {
for (URL registryURL : registryURLs) {
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())); Exporter<?> exporter = protocol.export(invoker);
exporters.add(exporter);
}
} else {
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); Exporter<?> exporter = protocol.export(invoker);
exporters.add(exporter);
}
}
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
参数ref指向的是dubbo:service配置中ref中指定的服务对象,interfaceClass是该服务的接口,第三个参数则是该服务的访问路径。
Exporter<?> exporter = protocol.export(invoker); // 最终将invoker暴露
Dubbo学习-源码学习的更多相关文章
- python 协程库gevent学习--源码学习(一)
总算还是要来梳理一下这几天深入研究之后学习到的东西了. 这几天一直在看以前跟jd对接的项目写的那个gevent代码.为了查错,基本上深入浅出了一次gevent几个重要部件的实现和其工作的原理. 这里用 ...
- Dubbo源码学习--服务是如何引用的
ReferenceBean 跟服务引用一样,Dubbo的reference配置会被转成ReferenceBean类,ReferenceBean实现了InitializingBean接口,直接看afte ...
- Dubbo源码学习--注册中心分析
相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 注册中心 关于注册中心,Dubbo提供了多个实现方式,有比较成熟的使用zookeeper 和 redis 的 ...
- Dubbo源码学习--服务是如何发布的
相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 ServiceBean ServiceBean 实现ApplicationListener接口监听Conte ...
- Dubbo源码学习--集群负载均衡算法的实现
相关文章: Dubbo源码学习文章目录 前言 Dubbo 的定位是分布式服务框架,为了避免单点压力过大,服务的提供者通常部署多台,如何从服务提供者集群中选取一个进行调用, 就依赖Dubbo的负载均衡策 ...
- Dubbo源码学习文章目录
目录 Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 Dubbo源码学习--注册中心分析 Dubbo源码学习--集群负载均衡算法的实现
- Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题
Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题 相关文章: Dubbo源码学习文章目录 前言 主要是前一阵子换了工作,第一个任务就是解决目前团队在 Dubbo 停机时产生的问题 ...
- Dubbo源码学习总结系列一 总体认识
本文写作时,dubbo最高版本是V2.6.0. 写这篇文章主要想回答以下4个问题: 一.dubbo是什么?完成了哪些主要需求? 二.dubbo适用于什么场景? 三.dubbo的总体架构是什么样的? ...
- Dubbo源码学习(二)
@Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...
随机推荐
- spring与mybatis(oracle)整合
今天闲着无聊把项目拆解开,抽出了spring与mybatis部分.做了个demo,希望对初学者有些帮助,另外整个demo是从项目中完整剥离下来的,里面的架构大家也可以参考一下. 先是完整的项目图 首先 ...
- 【leetcode82】Linked List Cycle
题目描述: 判断有序list是不是环 要求: 时间复杂度o(n) 原文描述: Given a linked list, determine if it has a cycle in it. Follo ...
- Java中Set的contains()方法
Java中Set的contains()方法 -- hashCode与equals方法的约定及重写原则 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashCode() a ...
- (NO.00001)iOS游戏SpeedBoy Lite成形记(九)
我们回到matchRun方法中去尝试第一次修改,部分代码如下: CCActionMoveBy *moveBy = [CCActionMoveBy actionWithDuration:duration ...
- (三十三)Xcode项目的重要工程文件
1.Supporting files内有一个Xxx-Info.plist文件(旧版本Xcode的配置文件叫Info.plist).因此自定义的plist不要带Info关键词. 这个plist是系统的全 ...
- 说说nio----1
既然说到了nio,就得谈以下几个问题 为什么会出现新io,"旧io"有什么问题吗? ok,一步一步来,先给大家看几个例子: 1单线程的服务器程序 import java.net.* ...
- linux下用gtk+写比赛赌博GUI小游戏
游戏界面全部由gtk的GUI完成,没有使用openGL之类的高端货. 游戏玩法就是8位选手比赛跑步,你可以在赛前赌哪位选手会赢,如果输了cash会被扣除,反之cash会增加. 无聊写了3个选项:小数时 ...
- nfc近场通信
NFC简介: Near Field Communication 近场通信,是一种数据传输技术. 与wifi.蓝牙.红外线等数据传输技术的一个主要差异就是有效距离一般不能超过4cm. NFC支持3种工作 ...
- Linux - grep的一些进阶选项
[root@www ~]# grep [-A] [-B] [--color=auto] '搜寻字串' filename 选项与参数: -A :后面可加数字,为 after 的意思,除了列出该行外,后续 ...
- Nginx的内部(进程)模型
nginx是以多进程的方式来工作的,当然nginx也是支持多线程的方式的,只是我们主流的方式还是多进程的方式,也是nginx的默认方式.nginx采用多进程的方式有诸多好处. (1)nginx在启动后 ...