Exchange信息交换层
1、Exchange层的类分析
ReferenceCountExchangeClient:将请求交HeaderExchangeClient处理,不进行任何其他操作。
HeaderExchangeClient:提供心跳检查功能;将send、request、close等事件转由HeaderExchangeChannel处理,HeaderExchangeChannel对象中的Channel为所选的NIO框架对应的client对象;以request为例,调用流程如下:HeaderExchangeClient. request(Object request)--->HeaderExchangeChannel. request(Object request)-->(NettyClient)AbstractPeer.send(Object message)-->(NettyClient)AbstractClient. send(Object message, boolean sent)。
HeaderExchangeChannel:主要是完成同步转异步。在request(Object request, int timeout)方法中,将请求转换成Request对象,将请求消息设置到data属性上,构建DefaultFuture对象,调用NIO框架对应的Client对象(默认选择NettyClient)的send方法将请求消息发送出去,返回DefultFuture对象。
NettyClient:完成消息的发送。在调用链的最后一个方法AbstractClient. send(Object message, boolean sent)中,首先通过调用NettyClient.getChannel()获取NettyChannel对象,在构建改对象时封装了NIOSocketChannel对象(在初始化NettyClient对象时,根据nettyclient与server建立连接时获取的socket通道)、统一数据模型URL以及channelHandler对象(NettyClient对象自身);然后,调用NettyChannel对象的send方法,将Request消息写入NIOSocketChannel通道中,完成消息发送。
HeaderExchangeServer:提供心跳检查功能;启动心跳监测线程池,该线程池初始化了一个线程,在线程中调用线程类HeartBeatTask进行心跳检查,HeartBeatTask处理心跳的规则:
1)若通道的最新的写入时间或者最新的读取时间与当前时间相比,已经超过了心跳间隔时间,则发送心跳请求;
2)如果通道的最新的读取时间与当前时间相比,已经超过了心跳的超时时间,对于客户端来说则重连;对于服务端来说则关闭通道。
2 多线程并发请求与单一长连接协同工作
如果客户端多线程并发请求的话,服务端通过单一长连接接受并返回响应信息,如果客户端不加控制就会导致通道中的数据变成无序,无法正确的处理请求。为此,Dubbo给每个请求添加了一个唯一标识ID,服务端响应请求也要携带此ID,供客户端多线程领取对于的响应数据,主要采用了多线程编程中的Future模式来解决此问题。客户端的实现具体如下:
1)当客户端的发起远程请求,最终调用HeaderExchangeClient.request方法,在该方法中调用HeaderExchangeChannel.request方法,并返回DefaultFuture对象。首先创建Request对象,请求消息作为Data值,并创建了唯一标识ID;然后在初始化DefaultFuture对象的过程中,将自身this对象以及channel对象存入全局变量DefaultFuture. FUTURES:ConcurrentHashMap和 DefaultFuture.CHANNELS:ConcurrentHashMap中,以标识ID为key值;代码如下:
2)该方法返回DefaultFuture对象给客户端请求线程,该线程会在DefaultFuture对象的get方法上面阻塞,有两种情况会唤醒该线程:1)接收到响应消息并调用received方法,根据响应消息中返回的ID从前面的ConcurrentHashMap里面get(ID)获取DefaultFuture对象,然后更新该对象的Response变量的值;2)RemotingInvocationTimeoutScan线程,定时扫描响应是否超时,若超时,则从FUTURES:ConcurrentHashMap中删掉Future对象并且将Response变量设置为超时信息。
3 同步转异步的逻辑
<dubbo:reference> 或 <dubbo:service> 标签中 async 属性表示是否异步调用; return 表示是否需要返回值。一、DubboInvoker. doInvoke的方法
在消费端发起请求后,调用至DubboInvoker类的doInvoke方法时,进行同步或异步调用的处理逻辑,具体逻辑如下:
1)当return=false时,发送消息后直接返回空RpcResult对象;
2)当async=true时,即异步操作,则调用request方法后(由HeaderExchangeChannel类的request方法处理,在该方法发送请求之后立即返回DefaultFuture对象)将返回的DefaultFuture对象用FutureAdapter类封装,并存入本地线程类ThreadLocal<RpcContext>的future变量中,并返回空RpcResult对象;在过滤器FutureFilter中异步处理返回响应结果。从而实现了同步转异步的逻辑。
3)当async=false时,即同步模式,在发送请求之后返回DefaultFuture对象,并调用该对象的get方法,该线程在此方法中阻塞,等待响应结果。
二、 FutureFilter内的逻辑
<dubbo:method>标签中async属性表示是否异步执行; oninvoke表示方法执行前的拦截方法;onreturn表示方法执行返回后的拦截方法;onthrow表示方法执行有异常的拦截方法;
FutureFilter为客户端的过滤器,只有客户端才使用该过滤器。在FutureFilter的invoke方法中,首先调用oninvoke属性配置的方法;然后调用invoker链的invoke方法;最后调用onreturn和onthrow配置的方法;
1)当async=true时表示异步执行,获取本地线程类ThreadLocal<RpcContext>的DefaultFuture对象,设置该对象的回调变量callback(该回调变量的值设置为实现了ResponseCallback接口的匿名类,匿名类实现了ResponseCallback接口的done和caught方法,这两个方法中主要是调用消费端在标签中配置的onreturn和onthrow方法),在DefaultFuture对象中若收到响应之后调用回调类的done方法。
2)当async=false时表示同步,在调用完invoker链的invoke方法并获得调用的响应消息之后继续调用客户端配置的onreturn和onthrow方法。