Dubbo概述

dubbo框架提供多协议远程调用,服务提供方可以是分布式部署。dubbo框架可以很简单的帮我们实现微服务。

此处援引官网上图片

dubbo分为客户端和服务提供方

服务方将服务注册到注册中心

客户端从注册中心获取已注册服务访问方式

客户端通过指定协议访问服务提供方

根据dubbo架构,源码分析我们主要切入点是:

  1. dubbo配置如何生效
  2. 客户端如何调用服务
  3. 注册的服务如何保证被调用到
  4. 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学习-源码学习的更多相关文章

  1. python 协程库gevent学习--源码学习(一)

    总算还是要来梳理一下这几天深入研究之后学习到的东西了. 这几天一直在看以前跟jd对接的项目写的那个gevent代码.为了查错,基本上深入浅出了一次gevent几个重要部件的实现和其工作的原理. 这里用 ...

  2. Dubbo源码学习--服务是如何引用的

    ReferenceBean 跟服务引用一样,Dubbo的reference配置会被转成ReferenceBean类,ReferenceBean实现了InitializingBean接口,直接看afte ...

  3. Dubbo源码学习--注册中心分析

    相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 注册中心 关于注册中心,Dubbo提供了多个实现方式,有比较成熟的使用zookeeper 和 redis 的 ...

  4. Dubbo源码学习--服务是如何发布的

    相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 ServiceBean ServiceBean 实现ApplicationListener接口监听Conte ...

  5. Dubbo源码学习--集群负载均衡算法的实现

    相关文章: Dubbo源码学习文章目录 前言 Dubbo 的定位是分布式服务框架,为了避免单点压力过大,服务的提供者通常部署多台,如何从服务提供者集群中选取一个进行调用, 就依赖Dubbo的负载均衡策 ...

  6. Dubbo源码学习文章目录

    目录 Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 Dubbo源码学习--注册中心分析 Dubbo源码学习--集群负载均衡算法的实现

  7. Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题

    Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题 相关文章: Dubbo源码学习文章目录 前言 主要是前一阵子换了工作,第一个任务就是解决目前团队在 Dubbo 停机时产生的问题 ...

  8. Dubbo源码学习总结系列一 总体认识

    本文写作时,dubbo最高版本是V2.6.0.  写这篇文章主要想回答以下4个问题: 一.dubbo是什么?完成了哪些主要需求? 二.dubbo适用于什么场景? 三.dubbo的总体架构是什么样的? ...

  9. Dubbo源码学习(二)

    @Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...

随机推荐

  1. Uva - 810 - A Dicey Problem

    根据状态进行bfs,手动打表维护骰子滚动. AC代码: #include <iostream> #include <cstdio> #include <cstdlib&g ...

  2. Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

    Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...

  3. 【leetcode81】Product of Array Except Self

    题目描述: 给定一个长度为n的整数数组Array[],输出一个等长的数组result[],这个输出数组,对应位置i是除了Array[i]之外,其他的所有元素的乘积 例如: given [1,2,3,4 ...

  4. (NO.00001)iOS游戏SpeedBoy Lite成形记(二十一)

    现在游戏中如果钱用光了赌场也是不管的,所以我们要加上Game Over的逻辑. 出现游戏结束条件很简单,就是GameState的totalMoney <= 0.而在游戏结束时我们要做些什么呢?有 ...

  5. ListView中ConvertView和ViewHolder

    1.概述 ListView是Android中非常常见的控件通过Adapter架起数据与界面显示的桥梁,MVC思想在其中得到了很好地体现: M:model 数据模型    添加到ListView中显示的 ...

  6. 【linux】mkfifo 命令创建命名管道实现进程之间通信

    mkfifo 命令 mkfifo命令创建一个FIFO特殊文件,是一个命名管道(可以用来做进程之间通信的桥梁) 管道也是一种文件,一般是linux中的一个页大小,4k,管道数据一旦被读取就没了.(管道大 ...

  7. RecyclerView实现瀑布流效果(二)

    在上篇中我们知道RecyclerView中默认给我们提供了三种布局管理器,分别是LinearLayoutManager.GridLayoutManager.StaggeredGridLayoutMan ...

  8. shell的date命令:使用方法,以及小时、分钟的计算

    shell命令格式严格,不像python那样命令行中可以添加空格.如等号两边无空格.有多余空格错误,日期date命令就是最明显的例子. 命令格式: date [-u] [-d datestr] [-s ...

  9. 《java入门第一季》之面向对象(修饰符的概念和总结)

    还是由于eclipde等ide的强大功能,会自动提示你修饰符是否可行.所以对修饰符的作用了解即可: 修饰符:         权限修饰符:private,默认的,protected,public    ...

  10. Material Design之CoordinatorLayout+AppBarLayout实现上滑隐藏ToolBar

    ok,今天继续更新Material Design系列!!! 废话不说,先看看效果图吧: 好了,现在来讲讲上图是怎么实现的吧!讲之前先讲讲几个控件: CoordinatorLayout  该控件也是De ...