阿里巴巴Dubbo实现的源码分析

  1. Dubbo概述

Dubbo是阿里巴巴开源出来的一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及作为SOA服务治理的方案。它的核心功能包括:

remoting:远程通讯基础,提供对多种NIO框架抽象封装,包括“同步转异步”和“请求-响应”模式的信息交换方式。

Cluster: 服务框架核心,提供基于接口方法的远程过程调用,包括多协议支持,并提供软负载均衡和容错机制的集群支持。

registry: 服务注册中心,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

由于Dubbo团队的文档和代码都非常优秀,所以更多关于dubbo的方方面面请参考网站http://code.alibabatech.com/wiki/display/dubbo/Home-zh。

这里我们只是补充一下从源码具体实现角度来看的某些细节方面,包括Invoker、ExtensionLoader等方面。任何官方已经介绍过的细节,我们不做画蛇添足,官方文档已经足够详实了,这篇文档的定位是补充实现的相关细节,是基于我在往Dubbo添加web service协议过程中,所碰到过的一些困难。

  1. 服务提供者暴露一个服务的详细过程

    上图是服务提供者暴露服务的主过程:

首先ServiceConfig类拿到对外提供服务的实际类ref(如:HelloWorldImpl),然后通过ProxyFactory类的getInvoker方法使用ref生成一个AbstractProxyInvoker实例,到这一步就完成具体服务到Invoker的转化。接下来就是Invoker转换到Exporter的过程。

Dubbo处理服务暴露的关键就在Invoker转换到Exporter的过程(如上图中的红色部分),下面我们以Dubbo和RMI这两种典型协议的实现来进行说明:

#Dubbo的实现

Dubbo协议的Invoker转为Exporter发生在DubboProtocol类的export方法,它主要是打开socket侦听服务,并接收客户端发来的各种请求,通讯细节由Dubbo自己实现。

#RMI的实现

RMI协议的Invoker转为Exporter发生在RmiProtocol类的export方法,它通过Spring或Dubbo或JDK来实现RMI服务,通讯细节这一块由JDK底层来实现,这就省了不少工作量。

  1. 服务消费者消费一个服务的详细过程

    上图是服务消费的主过程:

首先ReferenceConfig类的init方法调用Protocol的refer方法生成Invoker实例(如上图中的红色部分),这是服务消费的关键。接下来把Invoker转换为客户端需要的接口(如:HelloWorld)。

关于每种协议如RMI/Dubbo/Web service等它们在调用refer方法生成Invoker实例的细节和上一章节所描述的类似。

  1. 满眼都是Invoker

由于Invoker是Dubbo领域模型中非常重要的一个概念,很多设计思路都是向它靠拢。这就使得Invoker渗透在整个实现代码里,对于刚开始接触Dubbo的人,确实容易给搞混了。

 下面我们用一个精简的图来说明最重要的两种Invoker:服务提供Invoker和服务消费Invoker:


为了更好的解释上面这张图,我们结合服务消费和提供者的代码示例来进行说明:

#服务消费者代码

上面代码中的’DemoService’就是上图中服务消费端的proxy,用户代码通过这个proxy调用其对应的Invoker(DubboInvoker、 HessianRpcInvoker、 InjvmInvoker、 RmiInvoker、 WebServiceInvoker中的任何一个),而该Invoker实现了真正的远程服务调用。

上面这个类会被封装成为一个AbstractProxyInvoker实例,并新生成一个Exporter实例。这样当网络通讯层收到一个请求后,会找到对应的Exporter实例,并调用它所对应的AbstractProxyInvoker实例,从而真正调用了服务提供者的代码。

Dubbo里还有一些其他的Invoker类,但上面两种是最重要的。

  1. ExtensionLoader的完整分析

ExtensionLoader是Dubbo中一个非常重要的类,刚接触Dubbo源码的人看这个类的时候也多少会有点困惑,这个类非常重要,它就像是厨房里的“大厨”,按照用户的随时需要把各种“食材”烹调出来。

我们结合具体代码详细说一下ExtensionLoader的实现,下面是ServiceConfig类里的一行代码:

private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

   上面代码的程序流程图如下所示(假定是第一次执行这行代码):


在这个过程中最重要的两个方法是getExtensionClasses和createAdaptiveExtensionClass(图中红色部分),下面详细对这两个方法进行分析:

#getExtensionClasses

这个方法主要读取META-INF/services/目录下对应文件内容,在本示例代码中,是读取META-INF/services/com.alibaba.dubbo.rpc.Protocol文件中的内容,具体内容如下:

com.alibaba.dubbo.registry.support.RegistryProtocol

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper

com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper

com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol

com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol

com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol

com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol

com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol

它分析该文件中的每一行(每一行对应一个类),分析这些类,如果发现有哪个类的Annotation是@Adaptive,则找到对应的AdaptiveClass了,但由于Protocol文件里没有哪个类的Annotation是@Adaptive,所以在这个例子中该方法没找到对应的AdaptiveClass。

#createAdaptiveExtensionClass

该方法是在getExtensionClasses方法找不到AdaptiveClass的情况下被调用,该方法主要是通过字节码的方式在内存中新生成一个类,它具有AdaptiveClass的功能,Protocol就是通过这种方式获得AdaptiveClass类的。

AdaptiveClass类的作用是能在运行时动态判断具体是要调用哪个类的方法,更多关于AdaptiveClass的内容请参考Dubbo官方文档。

时间: 2024-11-05 17:28:25

阿里巴巴Dubbo实现的源码分析的相关文章

dubbo源码分析系列(4)dubbo通信设计

1 系列目录 dubbo源码分析系列(1)扩展机制的实现 dubbo源码分析系列(2)服务的发布 dubbo源码分析系列(3)服务的引用 dubbo源码分析系列(4)dubbo通信设计 2 NIO通信层的抽象 目前dubbo已经集成的有netty.mina.grizzly.先来通过案例简单了解下netty.mina编程(grizzly没有了解过) 2.1 netty和mina的简单案例 netty原本是jboss开发的,后来单独出来了,所以会有两种版本就是org.jboss.netty和io.n

dubbo源码分析系列(1)扩展机制的实现

1 系列目录 dubbo源码分析系列(1)扩展机制的实现 dubbo源码分析系列(2)服务的发布 dubbo源码分析系列(3)服务的引用 dubbo源码分析系列(4)dubbo通信设计 2 SPI扩展机制 站在一个框架作者的角度来说,定义一个接口,自己默认给出几个接口的实现类,同时允许框架的使用者也能够自定义接口的实现.现在一个简单的问题就是:如何优雅的根据一个接口来获取该接口的所有实现类呢? 这就需要引出java的SPI机制了 2.1 SPI介绍与demo 这些内容就不再多说了,网上搜一下,一

dubbo源码分析系列(3)服务的引用

1 系列目录 dubbo源码分析系列(1)扩展机制的实现 dubbo源码分析系列(2)服务的发布 dubbo源码分析系列(3)服务的引用 dubbo源码分析系列(4)dubbo通信设计 2 服务引用案例介绍 先看一个简单的客户端引用服务的例子,dubbo配置如下: <dubbo:application name="consumer-of-helloService" /> <dubbo:registry protocol="zookeeper" ad

dubbo源码分析系列(2)服务的发布

1 系列目录 dubbo源码分析系列(1)扩展机制的实现 dubbo源码分析系列(2)服务的发布 dubbo源码分析系列(3)服务的引用 dubbo源码分析系列(4)dubbo通信设计 2 dubbo与spring接入 dubbo的官方文档也说明了,dubbo可以不依赖任何Spring.这一块日后再详细说明,目前先介绍dubbo与Spring的集成.与spring的集成是基于Spring的Schema扩展进行加载 2.1 Spring对外留出的扩展 用过Spring就知道可以在xml文件中进行如

WebWork2源码分析

web Author: zhuam   昨晚一口气看完了夏昕写的<<Webwork2_Guide>>,虽然文档资料很简洁,但仍不失为一本好的WebWork2书籍,看的出作者的经验和能力都是非常的老道,在此向作者的开源精神致敬,并在此引用夏昕的那句话So many open source projects, Why not Open your Documents?   今天下载了最新的WebWork2版本, 开始了源码分析,这份文档只能算是我的个人笔记,也没时间细细校对,且个人能力有

JUnir源码分析(一)

一.引子 JUnit源码是我仔细阅读过的第一个开源项目源码.阅读高手写的代码能学到一些好的编程风格和实现思路,这是提高自己编程水平行之有效的方法,因此早就想看看这些赫赫有名的框架是怎么回事了.今天就拿最简单的JUnit下手,也算开始自己的源码分析之路.   JUnit作为最著名的单元测试框架,由两位业界有名人士协力完成,已经经历了多次版本升级(了解JUnit基础.JUnit实践).JUnit总体来说短小而精悍,有不少值得我们借鉴的经验在里面:但是也有一些不足存在,当然这对于任何程序来说都是难免的

java io学习(三) 管道的简介,源码分析和示例

管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例 本章,我们对java 管道进行学习. java 管道介绍 在java中,PipedOutputStream和PipedInputStream分别是管道输出流和管道输入流. 它们的作用是让多线程可以通过管道进行线程间的通讯.在使用管道通信时,必须将PipedOutputStream和PipedInputStream配套使用. 使用管道通信时,大致的流程是:我们在线程A中向PipedOutputStr

java io学习(二)ByteArrayOutputStream的简介,源码分析和示例

ByteArrayOutputStream的简介,源码分析和示例(包括OutputStream) 前面学习ByteArrayInputStream,了解了"输入流".接下来,我们学习与ByteArrayInputStream相对应的输出流,即ByteArrayOutputStream. 本章,我们会先对ByteArrayOutputStream进行介绍,在了解了它的源码之后,再通过示例来掌握如何使用它. ByteArrayOutputStream 介绍 ByteArrayOutputS

java io学习(一)ByteArrayInputStream的简介,源码分析和示例

ByteArrayInputStream的简介,源码分析和示例(包括InputStream) 我们以ByteArrayInputStream,拉开对字节类型的"输入流"的学习序幕. 本章,我们会先对ByteArrayInputStream进行介绍,然后深入了解一下它的源码,最后通过示例来掌握它的用法. ByteArrayInputStream 介绍 ByteArrayInputStream 是字节数组输入流.它继承于InputStream. 它包含一个内部缓冲区,该缓冲区包含从流中读取