前言
Dubbo作为一款阿里开源的高性能RPC调用框架,在重新维护后又焕发了生机,本篇博文主要分析Dubbo服务的调用过程,侧重点是服务调用方,Dubbo版本:2.7.8。
服务调用方执行逻辑
众所都周知,dubbo导入服务时,会为Refrence注解的对象创建动态代理,服务调用过程由动态代理类完成。首先来到Refrence代理对象的Handler:InvokerInvocationHandler,里面的invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
if ("toString".equals(methodName)) {
return invoker.toString();
} else if ("$destroy".equals(methodName)) {
invoker.destroy();
return null;
} else if ("hashCode".equals(methodName)) {
return invoker.hashCode();
}
} else if (parameterTypes.length == 1 && "equals".equals(methodName)) {
return invoker.equals(args[0]);
}
//构建方法调用体RpcInvocation
RpcInvocation rpcInvocation = new RpcInvocation(method, invoker.getInterface().getName(), args);
String serviceKey = invoker.getUrl().getServiceKey();
rpcInvocation.setTargetServiceUniqueName(serviceKey);
if (consumerModel != null) {
rpcInvocation.put(Constants.CONSUMER_MODEL, consumerModel);
rpcInvocation.put(Constants.METHOD_MODEL, consumerModel.getMethodModel(method));
}
//调用Invoker的invoke方法
return invoker.invoke(rpcInvocation).recreate();
}
duboo中Invoker是一个很重要的对象,不管是调用方还是提供方,Invoker都是方法调用的主要执行者,Invoker是一个层层包装的Invoker,最先来到Mock逻辑,MockClusterInvoker:
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;
//从url参数中判断需不需要进行mock
String value = getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim();
if (value.length() == 0 || "false".equalsIgnoreCase(value)) {
//不需要mock,继续调用链
result = this.invoker.invoke(invocation);
} else if (value.startsWith("force")) {
if (logger.isWarnEnabled()) {
logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + getUrl());
}
//直接进行mock
result = doMockInvoke(invocation, null);
} else {
//调用失败则进行mock
try {
result = this.invoker.invoke(invocation);
//fix:#4585
if(result.getException() != null && result.getException() instanceof RpcException){
RpcException rpcException= (RpcException)result.getException();
if(rpcException.isBiz()){
throw rpcException;
}else {
result = doMockInvoke(invocation, rpcException);
}
}
} catch (RpcException e) {
if (e.isBiz()) {
throw e;
}
if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + getUrl(), e);
}
result = doMockInvoke(invocation, e);
}
}
return result;
}
接下来到达AbstractClusterInvoker.invoke(invocation):把RpcContext中设置的Attachments添加到invocation对象上,调用路由链从服务目录上筛选出适合的服务Invoker,获得服务均衡策略loadbalance:
public Result invoke(final Invocation invocation) throws RpcException {
checkWhetherDestroyed();
//把RpcContext中设置的Attachments添加到invocation对象上
Map<String, Object> contextAttachments = RpcContext.getContext().getObjectAttachments();
if (contextAttachments != null && contextAttachments.size() != 0) {
((RpcInvocation) invocation).addObjectAttachments(contextAttachments);
}
//从服务目录根据路由获取对应的服务提供方,可能有多个
List<Invoker<T>> invokers = list(invocation);
//创建负载均衡器
LoadBalance loadbalance = initLoadBalance(invokers, invocation);
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
//FailoverClusterInvoker用负载均衡器继续往后调用
return doInvoke(invocation, invokers, loadbalance);
}
//FailoverClusterInvoker#doInvoke
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
List<Invoker<T>> copyInvokers = invokers;
checkInvokers(copyInvokers, invocation);
String methodName = RpcUtils.getMethodName(invocation);
//从url获取重试次数参数
int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
if (len <= 0) {
len = 1;
}
// retry loop.
RpcException le = null; // last exception.
List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
Set<String> providers = new HashSet<String>(len);
//容错逻辑,for循环多次调用,有一次成功则直接返回
for (int i = 0; i < len; i++) {
//Reselect before retry to avoid a change of candidate `invokers`.
//NOTE: if `invokers` changed, then `invoked` also lose accuracy.
if (i > 0) {
checkWhetherDestroyed();
copyInvokers = list(invocation);
// check again
checkInvokers(copyInvokers, invocation);
}
//用负载均衡器选出一个invoker,默认是加权随机策略
Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
//记录一下该invoker已经被调用过,在容错重试时会避免使用已经被用过的invoker
invoked.add(invoker);
RpcContext.getContext().setInvokers((List) invoked);
try {
//继续往后调用
Result result = invoker.invoke(invocation);
if (le != null && logger.isWarnEnabled()) {
//...
}
return result;
} catch (RpcException e) {
if (e.isBiz()) { // biz exception.
throw e;
}
le = e;
} catch (Throwable e) {
le = new RpcException(e.getMessage(), e);
} finally {
providers.add(invoker.getUrl().getAddress());
}
}
//...
}
}
接着来到InvokerWrapper.invoke(invocation),这个invoker啥都没做。。。
public Result invoke(Invocation invocation) throws RpcException {
return invoker.invoke(invocation);
}
然后会执行Filter链,执行完得到结果后,会获取ListenableFilter中的listener,执行listener的onResponse方法,看下构造过滤器链的逻辑:
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
//从SPI获取所有的filter
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (!filters.isEmpty()) {
//遍历每个filter,为每个filter创建一个invoker,在invoke方法中调用filter的invoke方法
//并层层包装,形成调用链
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
@Override
public Class<T> getInterface() {
return invoker.getInterface();
}
@Override
public URL getUrl() {
return invoker.getUrl();
}
@Override
public boolean isAvailable() {
return invoker.isAvailable();
}
@Override
public Result invoke(Invocation invocation) throws RpcException {
Result asyncResult;
try {
asyncResult = filter.invoke(next, invocation);
} catch (Exception e) {
if (filter instanceof ListenableFilter) {
ListenableFilter listenableFilter = ((ListenableFilter) filter);
try {
Filter.Listener listener = listenableFilter.listener(invocation);
if (listener != null) {
listener.onError(e, invoker, invocation);
}
} finally {
listenableFilter.removeListener(invocation);
}
} else if (filter instanceof Filter.Listener) {
Filter.Listener listener = (Filter.Listener) filter;
listener.onError(e, invoker, invocation);
}
throw e;
} finally {
}
return asyncResult.whenCompleteWithContext((r, t) -> {
if (filter instanceof ListenableFilter) {
ListenableFilter listenableFilter = ((ListenableFilter) filter);
Filter.Listener listener = listenableFilter.listener(invocation);
try {
if (listener != null) {
if (t == null) {
listener.onResponse(r, invoker, invocation);
} else {
listener.onError(t, invoker, invocation);
}
}
} finally {
listenableFilter.removeListener(invocation);
}
} else if (filter instanceof Filter.Listener) {
Filter.Listener listener = (Filter.Listener) filter;
if (t == null) {
listener.onResponse(r, invoker, invocation);
} else {
listener.onError(t, invoker, invocation);
}
}
});
}
@Override
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
走完过滤器后会来到AsyncToSyncInvoker这个invoker,是一个异步转同步的invoker,因为Dubbo默认都是异步调用,如果需要同步调用,得手动get:
public Result invoke(Invocation invocation) throws RpcException {
//继续往后调用
Result asyncResult = invoker.invoke(invocation);
try {
if (InvokeMode.SYNC == ((RpcInvocation) invocation).getInvokeMode()) {
//异步转同步,在get方法阻塞
asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
}
} catch (InterruptedException e) {
//...
} catch (ExecutionException e) {
Throwable t = e.getCause();
if (t instanceof TimeoutException) {
//超时异常
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " +
invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} else if (t instanceof RemotingException) {
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " +
invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} else {
//...
}
} catch (Throwable e) {
//...
}
return asyncResult;
}
接着来到AbstractInvoker.invoke(invocation),默认在这里会调用DubboInvoker的doInvoke方法,把结果包装成AsyncRpcResult:
public Result invoke(Invocation inv) throws RpcException {
//...
AsyncRpcResult asyncResult;
try {
//调用DubboInvoker的doInvoke
asyncResult = (AsyncRpcResult) doInvoke(invocation);
} catch (InvocationTargetException e) {
//如果出现异常也会包装成一个AsyncRpcResult
Throwable te = e.getTargetException();
if (te == null) {
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
} else {
if (te instanceof RpcException) {
((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
}
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, te, invocation);
}
} catch (RpcException e) {
if (e.isBiz()) {
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
} else {
throw e;
}
} catch (Throwable e) {
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
}
RpcContext.getContext().setFuture(new FutureAdapter(asyncResult.getResponseFuture()));
return asyncResult;
}
protected Result doInvoke(final Invocation invocation) throws Throwable {
ExchangeClient currentClient;
//如果有多个ExchangeClient,则轮询选出一个执行发送逻辑
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
try {
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
//计算超时时间
int timeout = calculateTimeout(invocation, methodName);
if (isOneway) {
//如果不关心结果,则调用send方法
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent);
return AsyncRpcResult.newDefaultAsyncResult(invocation);
} else {
//关心结果,使用request发送,返回一个CompletableFuture
ExecutorService executor = getCallbackExecutor(getUrl(), inv);
CompletableFuture<AppResponse> appResponseFuture =
currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);
// save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
FutureContext.getContext().setCompatibleFuture(appResponseFuture);
//把结果封装成AsyncRpcResult
AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);
result.setExecutor(executor);
return result;
}
} catch (TimeoutException e) {
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} catch (RemotingException e) {
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
继续调用,会来到HeaderExchangeChannel#request:
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
if (closed) {
throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
}
//创建一个request对象
Request req = new Request();
req.setVersion(Version.getProtocolVersion());
req.setTwoWay(true);
//设置data为方法调用体invocation
req.setData(request);
//构建一个future用来接收异步执行结果,DefaultFuture中持有channel引用
//DefaultFuture对象和req的id存入FUTURES中,FUTURES是一个Map,
//当HeaderExchangeHandler接收到结果时,会从这个Map中根据id获取到DefaultFuture对象,然后返回Response
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout, executor);
try {
//发送请求,这里的channel是AbstractPeer
channel.send(req);
} catch (RemotingException e) {
future.cancel();
throw e;
}
return future;
}
//AbstractPeer#send
public void send(Object message) throws RemotingException {
send(message, url.getParameter(Constants.SENT_KEY, false));
}
//AbstractClient#send
public void send(Object message, boolean sent) throws RemotingException {
if (needReconnect && !isConnected()) {
connect();
}
//拿到NettyChannel
Channel channel = getChannel();
if (channel == null || !channel.isConnected()) {
throw new RemotingException(this, "message can not send, because channel is closed . url:" + getUrl());
}
//发送
channel.send(message, sent);
}
NettyChannel是Dubbo在netty的NioSocketChannel基础上封装的channel,内部就是netty的channel:
public void send(Object message, boolean sent) throws RemotingException {
// whether the channel is closed
super.send(message, sent);
boolean success = true;
int timeout = 0;
try {
//调用NioSocketChannel以异步方式发送请求
ChannelFuture future = channel.writeAndFlush(message);
if (sent) {
// wait timeout ms
timeout = getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);
success = future.await(timeout);
}
Throwable cause = future.cause();
if (cause != null) {
throw cause;
}
} catch (Throwable e) {
//...
}
if (!success) {
//...
}
}
总结
Dubbo调用过程服务调用方的逻辑结束了,可以看到还是比较复杂的,要经过层层包装的invoker和filter,服务调用的核心思想时传递一个方法调用体invocation。