dubbo学习笔记2

这篇文章先来介绍一下dubbo的服务引用过程,说到服务引用,可以分为三种引用方式:1,本地引用,本地引用是直接查找本地缓存如果存在就直接使用该服务,因为有些服务它既是provider又是consumer,所以有可能是自己引用自己,所以就在自己的本地缓存自己的服务名称,节省了网络的开销,也是方便服务的调用。 2,网络直接引用,就是consumer这边直接写死provider的地址直接通过网络协议去寻找这个服务器的地址进行调用,这样的话就会比较依赖网络的速度以及可用性,也无法做服务端的负载均衡,可能不是很灵活。 3,通过注册中心进行服务的引用,这个就是dubbo使用的服务引用方式,consumer和provider都把自己注册到注册中心里面去,consumer通过拉去服务列表根据服务名称去定位自己需要的服务,再通过负载均衡去引用该服务。

继续说dubbo是怎样实现服务引用的,首先dubbo是一个rpc框架是悄无声息的调用远程服务所以就必然有一个类封装了复杂的服务发现以及具体的调用过程,就是invoker这个类,默认是懒汉式的他的调用入口就是referencebean的getobject()方法,先得到一个还没有组装内部细节的粗略的bean对象,之后去检查配置,调用referenceconfig的init()方法,把配置加载到一个map集合中,然后利用map来构建url地址,再通过url上的自适应扩展机制调用对应的protocol.refer得到invoker对象,是通过referenceconfig的creatproxy()方法来构建invoker对象,这个方法的具体过程是:先判断是否是本地引用,如果是的话直接构建本地协议的url地址进行服务调用,如果不是的话再看是否配置了url,如果配置了就根据配置的url协议组装生成url进行服务调用,如果没有配置就获取注册中心的url,根据map注册url,如果只有一个url那就直接根据协议生成invoker,如果有多个就遍历生成invoker,然后再由staticdirectory封装一下,通过cluster合并成一个invoker。

之后再调用registryprotocol的refer()方法,主要是获取注册中心实例,调用dorefer()进行真正的refer。生成registrydirectory这个类,这个类里有注册中心的实例,并且实现了notifylistener接口,也可以用于注册中心的监听。然后向注册中心注册自己的信息,然后向注册中心订阅providers节点,configurators 节点 和 routers 节点,收取这几点节点的信息,然后就获取了provider的信息,根据具体的协议调用refer方法,创建invoker,里面包含 netty client,因为是通过netty这个框架来进行网络通信,然后通过cluster合并invoker,最后调用proxyfactory的getproxy()封装得到的invoker,最终得到代理对象,之后就是这个代理类去做具体的方法调用,使得接口使用者无感知。

接下来说说dubbo整个的服务调用过程,先想个大致的流程就是客户端把自己想调用的方法名字以及传入的参数,通过网络传送给服务器端,然后服务器端去解析这些数据,然后使用具体的实现类去执行这些方法,得到结果后再通过网络传回客户端。

我们再来细致的看下这个过程,首先网络中传输的都是二进制数据,但是我的客户端和服务端肯定看不懂,需要转换成自己能够识别的语言,这样就需要统一一个标准,就是约定我们用什么语言两边都能看懂,所以需要定义协议,在网络传输的应用层一般有三种类型的协议,1,固定长度形式,指的是协议规定传输的数据单元长度是固定的,就是指读到我们规定长度的数据后就开始解析。这样的优点就是效率比较高,一直读够了就停下来,缺点就是太死板了不够灵活,我要发送的数据每次都不是固定的,超过了发不了,不够的话还得补一些空白字符,浪费了空间。  2,特殊字符隔断形式,就是协议规定一个特殊的字符,读到它就停止开始解析,但是这样也有一个不好的点,就是万一操作失误在要发送的数据中间使用了该特殊字符,就会出现错误。  3,header+body的形式,就是头部的长度是固定的,会在头部中标明body的长度,这样先按固定长度解析头部,得到身体的长度len之后就可以顺利解析body了。

其次网络中传输的是字节流,我们需要把java对象转换成字节流,收到以后再转回Java对象,需要规定使用的序列化协议,序列化大致分为两类,一是字符型的,二是二进制流的。字符型的就是xml,json,优点就是对人友好,方便理解调试,缺点就是传输的效率较低,有许多冗余的东西,比如说json的括号。二进制流的,优点就是传输速度较快,数据较为紧凑,方便机器识别传输,缺点就是对人不友好,我们程序员看不懂,难以调试更改。

最后根据上述的这些细节,再来细粒度的说下服务的调用过程,首先客户端调用接口的某个方法,然后通过上述的服务引用过程产生一个代理类,实际调用的是这个代理类,代理类会通过cluster从directory中获取一堆的invoker,然后进行router的过滤,然后再通过SPI得到loadbalance进行负载均衡,现在已经得到了我们需要调用的远程服务的invoker了,此时根据具体使用的协议构造请求头,再把具体要传送的数据通过序列化转换成相应的格式封装到请求体中,再通过netty client进行网络传输,服务器端的netty server 接收到数据之后,根据协议进行反序列化得到java对象,再交给dispatcher进行消息的分发,找到对应的业务线程池,业务线程会根据消息的类型判断后得到servicekey,然后从前面暴露服务生成的exportermap中得到对应的invoker,然后调用真实的实现类,最终将结果返回,因为是异步的被框架封装成了同步,所以根据请求和响应的同一个id找到存贮起来的future,然后塞入响应在唤醒等待future的线程,完成一次远程调用的全过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值