Dubbo通讯机制源码解析
dubbo底层运用netty发送接收消息源码分析—
服务消费者
dubbo的消费者端netty默认是启动一个socketChannel(也可以配置多个channel),消费者端的消费相当于是多线程调用channel的send()方法,深入dubbo中的netty源码详解:
直接跳到NettyClientHandler的write()方法这里调用的是WrapperChannelHandler的sent()方法
进入到HeaderExchangeHandler的sent()方法
*this.handler.sent()就是发送请求到提供者nettyserver的操作了。*
主要看这个DefaultFuture.sent()这个方法,这个就是实现同步调用的关键了,因为channel的channelRead()是托管给eventLoop执行的,eventLoop是单线程执行接收消息,像dubbo这样复用长连接channel的多线程发送但是单线程接收,同步调用的话无法知道哪个返回结果是属于哪个线程的,所以dubbo的实现就是为每个requestId绑定一个future,future类似juc包里的一个异步但是可以通过get()方法阻塞获取返回结果的类在调用的时候获取。(看另一篇文章)
当服务调用的时候DubboInvoker.invoke()会同步获取该请求id对应的返回结果(future.get()),最终会调用HeaderExchangeChannel.request的方法,可以看到在这个方法里新建了request对象然后绑定future,供外部get()阻塞获取返回结果。
当消费者收到返回的时候netty会调用HeadeExchangeHandler的handlerResponse()方法
*invokeCallback方法会唤醒defaultFuture的get方法*
服务提供者
这里在new的时候会初始化一个线程池,这个线程池就是专门用来处理业务的,消费着的一些channel调用都是往线程池里提交任务。
*nettyserver在收到请求后回调用channelRead()方法(一般客户端和服务端是单一长连接,所以nettyserver也只会有一个eventLoop处理这个channel),进入到MultiMessageHandler的revrived()方法*
进入AllCahnnelHandler的received()方法
这里就可以看到是netty服务端是把请求扔到线程池中处理,前面用一个线程接收请求参数(channel.isReadable()该channel是否有butebuf可读,如果返回true则把该请求扔到线程中中),不然单线程处理业务请求太吃力
对应一个run()方法,里面是如何处理各种的请求