1. 环境搭建
-
代码已经上传至 https://github.com/masteryourself/dubbo ,分支名称是
masteryourself-2.7.3-release
-
provider 是
dubbo-demo-xml-provider
工程,启动类是Application
-
consumer 是
dubbo-demo-xml-consumer
工程,启动类是Application
2. 源码解析
2.1 流程预览
2.1.1 consumer 端
// 1. 由于是动态代理,所以任何方法都会被 InvokerInvocationHandler 的 【invoke】 方法拦截
org.apache.dubbo.rpc.proxy.InvokerInvocationHandler#invoke
// 1.1(*) 执行 mock 逻辑
org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#invoke
// 1.1.1(*) 隐式传参,路由 invokers,初始化负载均衡策略,调用 doInvoke
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#invoke
// 1.1.1.1 查询出经过路由链过滤后的所有 Invokers
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#list ->
org.apache.dubbo.rpc.cluster.directory.AbstractDirectory#list ->
org.apache.dubbo.registry.integration.RegistryDirectory#doList ->
// 循环所有的 routers,MockInvokersSelector -> TagRouter -> AppRouter -> ServiceRouter,依次调用 route 方法筛选 invokers
org.apache.dubbo.rpc.cluster.RouterChain#route
// 1.1.1.2(*) 失败重试策略
org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke ->
// InvokerWrapper,无作用
org.apache.dubbo.rpc.protocol.InvokerWrapper#invoke ->
org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper.CallbackRegistrationInvoker#invoke ->
// 设置 consumer 调用信息
org.apache.dubbo.rpc.filter.ConsumerContextFilter#invoke ->
// oninvoke、onreturn、onthrow 处理逻辑
org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter#invoke ->
// 监控逻辑
org.apache.dubbo.monitor.support.MonitorFilter#invoke ->
// 无作用
org.apache.dubbo.rpc.listener.ListenerInvokerWrapper#invoke ->
// 异步转同步,调用 get 方法同步获取结果
org.apache.dubbo.rpc.protocol.AsyncToSyncInvoker#invoke ->
// 抽象处理逻辑
org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke
// 1.1.1.2.1 发送 dubbo 请求,获取结果
org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker#doInvoke
2.2.2 provider 端
// 1. netty server handler 接收请求
org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable#run ->
// 解码 message 信息
org.apache.dubbo.remoting.transport.DecodeHandler#received ->
// 判断消息类型,处理请求
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#received ->
// 处理请求和响应数据
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleRequest ->
// 调用 【DubboProtocol.ExchangeHandlerAdapter】 处理
org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter#reply ->
org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper.CallbackRegistrationInvoker#invoke ->
// 回声测试 filter
org.apache.dubbo.rpc.filter.EchoFilter#invoke ->
// 设置 classLoader
org.apache.dubbo.rpc.filter.ClassLoaderFilter#invoke ->
// 泛化调用 filter 处理
org.apache.dubbo.rpc.filter.GenericFilter#invoke ->
// 设置 context 上下文参数
org.apache.dubbo.rpc.filter.ContextFilter#invoke ->
// 链路追踪
org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter#invoke ->
// 服务端响应超时判断
org.apache.dubbo.rpc.filter.TimeoutFilter#invoke ->
// 监控
org.apache.dubbo.monitor.support.MonitorFilter#invoke ->
// 处理异常
org.apache.dubbo.rpc.filter.ExceptionFilter#invoke ->
// 无作用
org.apache.dubbo.rpc.protocol.InvokerWrapper#invoke ->
org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker#invoke ->
// 抽象处理逻辑
org.apache.dubbo.rpc.proxy.AbstractProxyInvoker#invoke ->
// 通过反射调用实现类的方法
org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getInvoker
2.3 流程详解
2.3.1 MockClusterInvoker#invoke(1.1)
org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;
// 从 url 中获取 mock 对应的值
String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim();
// 如果没有 value 或者 value 等于 false,则表示没有 mock 逻辑
if (value.length() == 0 || value.equalsIgnoreCase("false")) {
//no mock
result = this.invoker.invoke(invocation);
}
// 服务屏蔽:如果是以 force 开头,则表示强制 mock
else if (value.startsWith("force")) {
if (logger.isWarnEnabled()) {
logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
}
//force:direct mock
// mock 逻辑
result = doMockInvoke(invocation, null);
}
// 服务容错:先调用,如果调用失败才会进行 mock 逻辑
else {
//fail-mock
try {
result = this.invoker.invoke(invocation);
} catch (RpcException e) {
if (e.isBiz()) {
throw e;
}
if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
}
// mock 逻辑
result = doMockInvoke(invocation, e);
}
}
return result;
}
2.3.2 AbstractClusterInvoker#invoke(1.1.1)
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker
public Result invoke(final Invocation invocation) throws RpcException {
checkWhetherDestroyed();
// binding attachments into invocation.
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
// 隐式传参
if (contextAttachments != null && contextAttachments.size() != 0) {
((RpcInvocation) invocation).addAttachments(contextAttachments);
}
// 查询出经过路由链过滤后的所有 Invoker
List<Invoker<T>> invokers = list(invocation);
// 初始化负载均衡策略
LoadBalance loadbalance = initLoadBalance(invokers, invocation);
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
// 调用
return doInvoke(invocation, invokers, loadbalance);
}
2.3.3 FailoverClusterInvoker#doInvoke
org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker
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);
// 获取调用方法的次数,failover 默认是重试 2 次,+1 表示一共调用三次
int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
if (len <= 0) {
len = 1;
}
// retry loop.
RpcException le = null; // last exception.
// 表示已经调用过的 Invoker,重试时候避免再次选择到相同的 invoker
List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
Set<String> providers = new HashSet<String>(len);
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,它是 RegistryDirectory$InvokerDelegate 类型
Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
// 添加到 invoked 中,表示已经调用过
invoked.add(invoker);
RpcContext.getContext().setInvokers((List) invoked);
try {
// 调用 invoke 方法,先经过 InvokerWrapper 处理
Result result = invoker.invoke(invocation);
// 前面的出错只会打印 warn 日志
if (le != null && logger.isWarnEnabled()) {
logger.warn("Although retry the method " + methodName
+ " in the service " + getInterface().getName()
+ " was successful by the provider " + invoker.getUrl().getAddress()
+ ", but there have been failed providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ". Last error is: "
+ le.getMessage(), le);
}
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());
}
}
throw new RpcException(le.getCode(), "Failed to invoke the method "
+ methodName + " in the service " + getInterface().getName()
+ ". Tried " + len + " times of the providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
+ Version.getVersion() + ". Last error is: "
+ le.getMessage(), le.getCause() != null ? le.getCause() : le);
}