1.服务整体流程图
消费者通过代理对象(proxy查看:)对远程服务发起调用,经过一编码发送给服务端,服务端通过解码发送到dispatcher分发到线程池中,最后线程池调用具体的服务
2.服务调用
源码地址+注释,dubbo版本是2.6.x版本:https://github.com/adward-liu/dubbo/tree/2.6.x-liu
package com.alibaba.dubbo.common.bytecode;
import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.demo.DemoService;
import com.alibaba.dubbo.rpc.service.EchoService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class proxy0
implements ClassGenerator.DC,
EchoService,
DemoService {
public static Method[] methods;
private InvocationHandler handler;
public String sayHello(String string) {
Object[] arrobject = new Object[]{string};
//InvocationHandler 反射调用 arrobject 参数集合
Object object = this.handler.invoke(this, methods[0], arrobject);
return (String)object;
}
public Object $echo(Object object) {
Object[] arrobject = new Object[]{object};
Object object2 = this.handler.invoke(this, methods[1], arrobject);
return object2;
}
public proxy0() {
}
public proxy0(InvocationHandler invocationHandler) {
this.handler = invocationHandler;
}
}
使用arthas反编译之后的代码 获取的代理类:com.alibaba.dubbo.common.bytecode.proxy0,当调用sayHello的方法是,实际调用的是this.handler.invoke(this, methods[0], arrobject);方法,invoker实例
下面是该实例的具体代码
public class InvokerInvocationHandler implements InvocationHandler {
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return invoker.toString();
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return invoker.hashCode();
}
if ("equals".equals(methodName) && parameterTypes.length == 1) {
return invoker.equals(args[0]);
}
//创建netty发送对象的RpcInvocation
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
}
其中InvokerInvocationHandler中属性invoker是:MockClusterInvoker,其中设置服务降级mock,可以参照:https://www.jianshu.com/p/d71c7771b9c9,mocker具体配置:如果是force强制走mock,实现类是接口名+Mock
@Override
public Result invoke(Invocation invocation) throws RpcException {
//invocation RpcInvocation methodName, parameterTypes, arguments
Result result = null;
// //dubbo的服务降级策略,失败之后会走mock方法,打到服务降级的策略,https://www.jianshu.com/p/d71c7771b9c9
String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
if (value.length() == 0 || value.equalsIgnoreCase("false")) {
//no mock
//如果没有mock配置,不走mock逻辑
result = this.invoker.invoke(invocation);
} else if (value.startsWith("force")) {
if (logger.isWarnEnabled()) {
logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
}
//force:direct mock
//force开头,强制进行mock //这个force只能通过override触发 接口名+Mock
result = doMockInvoke(invocation, null);
} else {
//fail-mock
//服务降级
try {
result = this.invoker.invoke(invocation);
} catch (RpcException e) {
if (e.isBiz()) {
throw e;
} else {
if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
}
result = doMockInvoke(invocation, e);
}
}
}
return result;
}
invoker方法调用AbstractClusterInvoker
public Result invoke(final Invocation invocation) throws RpcException {
checkWhetherDestroyed();
LoadBalance loadbalance = null;
// binding attachments into invocation.
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
if (contextAttachments != null && contextAttachments.size() != 0) {
((RpcInvocation) invocation).addAttachments(contextAttachments);
}
//获取所有的invoker,参考RegistryDirectory中的dolist方法,后续详解
List<Invoker<T>> invokers = list(invocation);
if (invokers != null && !invokers.isEmpty()) {
//获取默认的负载均衡策略
loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
.getMethodParameter(RpcUtils.getMethodName(invocation), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
}
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
return doInvoke(invocation, invokers, loadbalance);
}
该方法主要就是为了获取invoker集合以及负载均衡的策略,doInoker主要的代码逻辑在DubboInvoker //TODO负载均衡策略
protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;
final String methodName = RpcUtils.getMethodName(invocation);
//添加path以及version信息
inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
inv.setAttachment(Constants.VERSION_KEY, version);
ExchangeClient currentClient;
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
try {
//获取调用方式
boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
if (isOneway) {
//异步调用 无返回值
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent);
RpcContext.getContext().setFuture(null);
return new RpcResult();
} else if (isAsync) {
//异步调用 有返回值
ResponseFuture future = currentClient.request(inv, timeout);
//FutureAdapter 适配器 将jdk中future与ResponseFuture结合 get实际调用的是ResponseFuture的get方法
RpcContext.getContext().setFuture(new FutureAdapter<Object>(future));
return new RpcResult();
} else {
//同步调用
RpcContext.getContext().setFuture(null);
//阻塞 直到获取到返回值 DefaultFuture 默认实现类
//发送消息
return (Result) currentClient.request(inv, timeout).get();
}
} 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);
}
}
doinoker默认是走同步调用(FailoverClusterInvoker 失败策略,后单独开一篇文章讲解),这里有个非常有意思的类是DefaultFuture,感觉像是jdk自带的模样,异步、同步的实现都在这个类中实现,贴出代码一目了然,比较重要的几个方法
RpcContext.getContext().setFuture(null);
//阻塞 直到获取到返回值 DefaultFuture 默认实现类
//发送消息
return (Result) currentClient.request(inv, timeout).get();
类DefaultFuture 堵塞代码
public class DefaultFuture implements ResponseFuture {
// invoke id.
private final long id;
private final Channel channel;
private final Request request;
private volatile long sent;
public DefaultFuture(Channel channel, Request request, int timeout) {
this.channel = channel;
this.request = request;
//这个id非常重要
this.id = request.getId();
this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
//通过id进行绑定
FUTURES.put(id, this);
CHANNELS.put(id, channel);
}
public static void received(Channel channel, Response response) {
try {
//根据id获取对应的future
DefaultFuture future = FUTURES.remove(response.getId());
if (future != null) {
future.doReceived(response);
} else {
logger.warn("The timeout response finally returned at "
+ (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))
+ ", response " + response
+ (channel == null ? "" : ", channel: " + channel.getLocalAddress()
+ " -> " + channel.getRemoteAddress()));
}
} finally {
CHANNELS.remove(response.getId());
}
}
@Override
public Object get(int timeout) throws RemotingException {
if (timeout <= 0) {
timeout = Constants.DEFAULT_TIMEOUT;
}
if (!isDone()) {
long start = System.currentTimeMillis();
lock.lock();
try {
//等待 直到处理完
while (!isDone()) {
//等待有消息返回的时候 signal
done.await(timeout, TimeUnit.MILLISECONDS);
if (isDone() || System.currentTimeMillis() - start > timeout) {
break;
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
if (!isDone()) {
throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
}
}
return returnFromResponse();
}
@Override
public boolean isDone() {
return response != null;
}
private Object returnFromResponse() throws RemotingException {
Response res = response;
if (res == null) {
throw new IllegalStateException("response cannot be null");
}
if (res.getStatus() == Response.OK) {
return res.getResult();
}
if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
throw new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage());
}
throw new RemotingException(channel, res.getErrorMessage());
}
}
思考一个问题,dubbo有如此多的请求,请求数据与返回数据是对应关系是怎么设计的呢?(提示DefaultFuture有个requestId,这个id与dubbo)答案见最后截图
消费端正式调用send方法currentClient.request(inv, timeout),我们可以HeaderExchangeChannel的request方法中看到netty发送request信息,有兴趣的可以看一下dubbo的数据包以及编解码
调用的整体类图
proxy0#sayHello(String)
—> InvokerInvocationHandler#invoke(Object, Method, Object[])
—> MockClusterInvoker#invoke(Invocation)
—> AbstractClusterInvoker#invoke(Invocation)
—> FailoverClusterInvoker#doInvoke(Invocation, List<Invoker<T>>, LoadBalance)
—> Filter#invoke(Invoker, Invocation) // 包含多个 Filter 调用
—> ListenerInvokerWrapper#invoke(Invocation)
—> AbstractInvoker#invoke(Invocation)
—> DubboInvoker#doInvoke(Invocation)
—> ReferenceCountExchangeClient#request(Object, int)
—> HeaderExchangeClient#request(Object, int)
—> HeaderExchangeChannel#request(Object, int)
—> AbstractPeer#send(Object)
—> AbstractClient#send(Object, boolean)
—> NettyChannel#send(Object, boolean)
—> NioClientSocketChannel#write(Object)
整体的消费端调用结束
当服务提供者接收到netty传来的信息就会解码,获取对应的类名、方法名以及参数名称数值,线程池分发调用具体的处理逻辑(AllChannelHandler),具体的执行逻辑在ChannelEventRunnable#run方法的decode
@Override
/*处理请求和响应消息,这里的 message 变量类型可能是 Request,也可能是 Response*/
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService cexecutor = getExecutorService();
try {
//ChannelEventRunnable处理
cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {
//TODO A temporary solution to the problem that the exception information can not be sent to the opposite end after the thread pool is full. Need a refactoring
//fix The thread pool is full, refuses to call, does not return, and causes the consumer to wait for time out
if(message instanceof Request && t instanceof RejectedExecutionException){
Request request = (Request)message;
if(request.isTwoWay()){
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}