dubbo源码分析之请求调用异步化原理
关键实现机制分析
一、核心原理:
-
Netty本身是异步的:所有I/O操作都返回
ChannelFuture
,不阻塞调用线程 -
CompletableFuture封装:Dubbo使用
CompletableFuture
封装异步操作结果 -
同步化接口:通过
get()
方法提供同步等待能力
二、代码分析:
// 从你选中的代码可以看出:
ExecutorService executor = getCallbackExecutor(getUrl(), inv);// 1. 这里是真正的异步调用,不会阻塞当前线程
CompletableFuture<AppResponse> appResponseFuture =currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);// 2. 封装成AsyncRpcResult,立即返回
AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);
result.setExecutor(executor);
return result; // 立即返回,不等待实际响应
三、关键对比:
Netty 的同步化模式:
// Netty 的同步化模式 - 会阻塞等待
ChannelFuture future = channel.writeAndFlush(message);
future.sync(); // 阻塞等待写操作完成
Dubbo 异步调用:
// Dubbo 异步调用 - 不阻塞
CompletableFuture<AppResponse> future = currentClient.request(inv, timeout, executor);
return new AsyncRpcResult(future, inv); // 立即返回异步结果
四、在当前代码中的体现:
- 异步请求发送:
currentClient.request()
立即返回CompletableFuture
- 链式处理:通过
thenApply()
进行类型转换,仍然是异步的 - 立即返回:
AsyncRpcResult
立即返回给调用者 - 用户控制同步化:调用者可以选择调用
result.get()
来同步等待
五、同步化的时机:
// 在用户代码中的同步化
AsyncRpcResult asyncResult = (AsyncRpcResult) invoker.invoke(invocation);
AppResponse response = asyncResult.get(); // 这里才是同步等待
总结:Dubbo没有直接使用Netty的sync()
方法进行阻塞,而是通过CompletableFuture
的异步编程模型,让用户自己决定何时进行同步等待,这样既保持了高性能的异步特性,又提供了同步编程的便利性。
注意:Dubbo在不同版本实现异步转同步的原理是不同的,但是开发迭代的基本思路是按照更设计更合理、技术更好、性能更优的方向演进的。