Dubbo原理(5)--服务调用流程
引用服务的流程:最终会为我们创建出一个代理对象;
那么代理对象如何进行方法(远程)的调用?
Dubbo官方文档里面有整个调用链的图:http://dubbo.apache.org/zh-cn/docs/dev/design.html
例如:
这个对象userService确实是一个代理对象,这个代理对象层层封装了各种invoker,invoker里面是我们真正要执行的功能方法;
如何执行如下:
public class InvokerInvocationHandler implements InvocationHandler {
private final Invoker<?> invoker;
...
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
...
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
}
1.进入要执行的方法,我们会先跳到InvokerInvocationHandler的invoke;
2.进来之后,我们会先拿到方法的信息、参数的类型信息等等;
3.下面有invoker.invoke,想要invoke执行,会把方法和参数封装成一个RPC执行的远程调用的对象;
4.invoker.invoke是如何实现的(见下)?
public class MockClusterInvoker<T> implements Invoker<T> {
...
@Override
public Result invoke(Invocation invocation) throws RpcException {
...
if (value.length() == 0 || value.equalsIgnoreCase("false")) {
//no mock
result = this.invoker.invoke(invocation);
} else if (value.startsWith("force")) {
...
} else {
//fail-mock
try {
result = this.invoker.invoke(invocation);
} catch (RpcException e) {
....
}
}
return result;
}
...
}
1.我们首先得到的是最外层的MockClusterInvoker类的invoke方法;
2.MockClusterInvoker类的:invoke里面又封装了FailoverClusterInvoker;
3.FailoverClusterInvoker其实就是集群容错的invoke。集群容错,当我们出现失败以后,会重试,重试其他的服务器;
4.继续执行,会跳到AbstractClusterInvoker的invoke方法;
public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
...
@Override
public Result invoke(final Invocation invocation) throws RpcException {
...
List<Invoker<T>> invokers = list(invocation);
if (invokers != null && !invokers.isEmpty()) {
loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
.getMethodParameter(invocation.getMethodName(), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
}
...
return doInvoke(invocation, invokers, loadbalance);
}
...
}
1.AbstractClusterInvoker的invoke方法在执行的时候,会有list(invocation),这个list方法是:我们在注册中心找到到底有几个invoker来执行(eg:可能有2.0.0版本和1.0.0版本),相当于找到了2个能执行的方法;
2.接下来来获取到loadbalance负载均衡机制(我们配置的默认的负载均衡机制);
3.接下来继续doInvoke;
4.doInvoke就是FailoverClusterInvoker的doInvoke方法;
public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {
...
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
...
for (int i = 0; i < len; i++) {
...
Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);
invoked.add(invoker);
...
try {
Result result = invoker.invoke(invocation);
...
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());
}
}
...
}
}
1.负载均衡拿到之后,会有select,依据负载均衡策略,随机选择一个invoker;
2.接下来有invoker.invoke,invoker里面有封装了一些filter。filter有可能在一开始代理对象里面要用invoker的时候封装一个filter(eg:要做缓存功能(结果缓存):cache;本地伪装:mock等)。接下来,invoker选中负载均衡之后,又进入了filter的环节,接下来就是各种统计信息。相当于最终,将所有filter都解除了之后,就剩下了DubboInvoker来进行远程调用;
public class DubboInvoker<T> extends AbstractInvoker<T> {
...
@Override
protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;
final String methodName = RpcUtils.getMethodName(invocation);
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 {
...
} catch (TimeoutException e) {
...
} catch (RemotingException e) {
...
}
}
...
}
1.DubboInvoker会拿到要执行的方法的信息,接下来会拿到客户端:ExchangeClient currentClient;
2.currentClient客户端在服务引用的时候暴露过一次(eg:我们当前要连向20882服务器);
3.方法执行超时,会报错,但是也会第二次重试等等;
---接Dubbo官方文档里面有整个调用链的图:
1.我们的代理对象proxy如果有做其他功能有filter介入;
2.我们使用cluster用来封装多个invoker的。如果有多个invoker的情况下,可以选择负载均衡机制,如果调用错了,还会有重试;
3.负载均衡在调用期间,还会有其他的filter介入,统计数据;
4.最终我们真正执行功能的是dubbo(protocol--协议)的invoker来进行调用;
5.调用的底层是client发送请求,client的底层就是netty客户端连接目标端口的服务器,来发送请求;
6.服务器请求收到数据之后,我们来解码,来整个返回,把我们整个返回数据,由代理对象交给我们;
本文地址:https://blog.csdn.net/dww161250020/article/details/107119541
上一篇: Linux安装MySQL5.7「转」