最近一个同学说遇到了一个 Dubbo 异步调用的问题,怀疑是个 Bug。提到 Bug 我可就不困了,说不定可以水,哦不...写一篇文章。
问题复现
public interface DemoService {
boolean isUser();
Boolean isFood();
}
2) 实现 Provider,为了简单,都返回 true,并且打了日志。
@Service
public class DemoServiceImpl implements DemoService {
@Override
public boolean isUser() {
System.out.println("server is user : true");
return true;
}
@Override
public Boolean isFood() {
System.out.println("server is food : true");
return true;
}
}
@RestController
public class DemoCallerService {
@Reference(injvm = false, check = false)
private DemoService demoService;
@GetMapping(path = "/isUser")
public String isUser() throws Exception {
BlockingQueue<Boolean> q = new ArrayBlockingQueue<>(1);
RpcContext.getContext().asyncCall(
() -> demoService.isUser()
).handle(
(isUser, throwable) -> {
System.out.println("client is user = " + isUser);
q.add(isUser);
return isUser;
});
q.take();
return "ok";
}
@GetMapping(path = "/isFood")
public String isFood() throws Exception {
BlockingQueue<Boolean> q = new ArrayBlockingQueue<>(1);
RpcContext.getContext().asyncCall(
() -> demoService.isFood()
).handle(
(isFood, throwable) -> {
System.out.println("client is food = " + isFood);
q.add(isFood);
return isFood;
});
q.take();
return "ok";
}
}
4)启动一个 Provider,再启动一个 Consumer 进行测试。
果然和提问的同学表现一致:
// client ...
client is user = false
// server ...
server is user : true
问题排查
// client ...
client is food = true
// server ...
server is food : true
com.alibaba.dubbo.remoting.exchange.support.DefaultFuture#doReceived
sc *.proxy0
jad org.apache.dubbo.common.bytecode.proxy0
//local invoke will return directly
server is user : true
client is user = true
public <T> CompletableFuture<T> asyncCall(Callable<T> callable) {
try {
try {
setAttachment(ASYNC_KEY, Boolean.TRUE.toString());
final T o = callable.call();
//local invoke will return directly
if (o != null) {
if (o instanceof CompletableFuture) {
return (CompletableFuture<T>) o;
}
if (injvm()) { // 伪代码
return CompletableFuture.completedFuture(o);
}
} else {
// The service has a normal sync method signature, should get future from RpcContext.
}
} catch (Exception e) {
throw new RpcException(e);
} finally {
removeAttachment(ASYNC_KEY);
}
} catch (final RpcException e) {
// ....
}
return ((CompletableFuture<T>) getContext().getFuture());
}
最后
- EOF -
1、我是一个Dubbo数据包...
2、《我想进大厂》之Dubbo普普通通9问
3、长文详解:DUBBO源码使用了哪些设计模式
看完本文有收获?请转发分享给更多人
关注「ImportNew」,提升Java技能
点赞和在看就是最大的支持❤️