Fork me on GitHub

duubo的proxy代理

Proxy层

image-20220701064957928

proxy层是dubbo中的动态代理层,主要是为了屏蔽dubbo内部Cluster、Protocol概念设计,能让业务层像调用本地方法一样去发起RPC调用。

  • 在Consumer层进行引用服务时,通过动态代理把引用的dubbo接口转化为Invoker对象,Dubbo内部也是通过Invoker和Cluster、Protocol层进行交互。

    • 对应着ProxyFactory的方法:
      1
      2
      3
      4
      5
      6
      7
      8
      9
          /**
      * create proxy.
      * 创建代理 在引用dubbo服务时使用,引用的最终是代理对象
      *
      * @param invoker
      * @return proxy
      */
      @Adaptive({PROXY_KEY})
      <T> T getProxy(Invoker<T> invoker) throws RpcException;
  • 在Provider层进行导出暴露服务时,通过动态代理实现Invoker对象和真正dubbo服务实现类的转换,进而调用到dubbo服务。

    • 对应着ProxyFactory的getInvoker方法
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      /**
      * create invoker.
      * 代理工程创建Invoker 在export导出服务时使用
      *
      * @param <T>
      * @param proxy
      * @param type
      * @param url
      * @return invoker
      */
      @Adaptive({PROXY_KEY})
      <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

客户端的代理逻辑

在客户端Invoker模型是Dubbo内部封装的客户端发起网络调用的模型,通过ProxyFactory.getProxy(invoker)生成代理对象供客户端业务引用调用,屏蔽了内部细节。

客户端于服务引用时调用的getProxy方法生成的代理类,可以看到都是将拦截逻辑用InvokerInvocationHandler实现,也就是消费端引用的dubbo远程对象,都是一个代理对象,会在发起调用时走到InvokerInvocationHandler的invoke方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
// object类方法直接调用
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);
// Invoker的url生成serviceKey
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对象 主要看几个层级的 @See 集群容错的ClusterInvoker、 Consumer端的Filter链、AbstractInvoke.invoke方法、DubboInvoker.doInvoke()方法
// 返回值 @See AsyncRpcResult
// invoke完成之后 调用调用结果的recreate()方法 如果存在异常 在客户端抛出对应的异常
return invoker.invoke(rpcInvocation).recreate();
}

服务端代理逻辑

在服务端也用到了动态代理和Invoker模型。服务端的Invoker代表可执行对象,provider端的真正dubbo实现类被封装为ProxyInvoker(通过ProxyFactory.getInvoker(proxy)方法,这里的proxy是dubbo真正实现类),对不同的dubbo接口服务实现都抽象为ProxyInvoker模型来实现调用。

为dubbo服务实现类生成代理也有jdk动态代理和Javassist动态代理两种实现。
无论哪种实现Dubbo服务实现类都会被AbstractProxyInvoker,调用invoke方法时,会委托给子类的doInvoke方法,两个代理框架有不一样的实现。

其中invoke方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Override
public Result invoke(Invocation invocation) throws RpcException {
try {
// 子类实现doInvoke方法 即具体的ProxyFactory实现 (jdk或者javassist)
// 比如 JavassistProxyFactory中实现doInvoke是通过调用字节码动态生成的Wrapper的子类 调用其invokeMethod方法
// 内部会调用dubbo服务实现类的方法
Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
// 基于value创建一个CompltableFuture
CompletableFuture<Object> future = wrapWithFuture(value);
CompletableFuture<AppResponse> appResponseFuture = future.handle((obj, t) -> {
// 根据dubbo返回值封装的future 注册一个任务 将真正返回值包装到AppResponse
AppResponse result = new AppResponse();
if (t != null) {
if (t instanceof CompletionException) {
result.setException(t.getCause());
} else {
result.setException(t);
}
} else {
result.setValue(obj);
}
return result;
});
// 包装一层AsyncRpcResult返回给上层Invoker
return new AsyncRpcResult(appResponseFuture, invocation);
} catch (InvocationTargetException e) {
if (RpcContext.getContext().isAsyncStarted() && !RpcContext.getContext().stopAsync()) {
logger.error("Provider async started, but got an exception from the original method, cannot write the exception back to consumer because an async result may have returned the new thread.", e);
}
return AsyncRpcResult.newDefaultAsyncResult(null, e.getTargetException(), invocation);
} catch (Throwable e) {
throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
}
}

doInvoke的两种实现:

  • jdkJdkRpcProxyFactory实现:就是用java反射调用具体的dubbo服务实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // JdkRpcProxyFactory.getInvoker
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
    // jdk反射 来封装dubbo服务实现类的代理封装
    return new AbstractProxyInvoker<T>(proxy, type, url) {
    @Override
    protected Object doInvoke(T proxy, String methodName,
    Class<?>[] parameterTypes,
    Object[] arguments) throws Throwable {
    // 直接反射调用
    Method method = proxy.getClass().getMethod(methodName, parameterTypes);
    return method.invoke(proxy, arguments);
    }
    };
    }
  • JavassistProxyFactory实现:利用Wrapper的invokeMethod方法封装实现调用具体的dubbo服务实现类。其中Wrapper是利用Javassist框架生成的动态代理类,来完成对dubbo服务实现类真正方法的调用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // getInvoker 服务导出时使用 封装dubbo服务实现类为invoker
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
    // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
    // 字节码生成的Wrapper实现类 对传入的proxy(export场景是dubbo服务实现类)进行包装
    final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
    return new AbstractProxyInvoker<T>(proxy, type, url) {
    // 实现doInvoke方法 会从AbstractProxyInvoker.invoke中调用
    @Override
    protected Object doInvoke(T proxy, String methodName,
    Class<?>[] parameterTypes,
    Object[] arguments) throws Throwable {
    // 调用Invoker.invoke方法时会委托给wrapper.invokeMethod方法
    return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
    }
    };

    // Invoker.invoke --> AbstractProxyInvoker.invoke --> AbstractProxyInvoker.doInvoke --> Wrapper.getWrapper.invokeMethod
    }

代理层总结

image-20220701064322108代理层在在dubbo-rpc-api包内,Consumer层的Proxy屏蔽了复杂的网络交互、集群策略、Dubbo内部的Invoker等概念,提供给上层业务是Dubbo接口,像本地方法一样的去发起远程调用;而Provider端的Wrapper的动态代理封装了不同的Dubbo服务实现类,统一转换为Dubbo的Invoker模型。代理层让业务接口和Dubbo框架无缝对接。

-------------本文结束感谢您的阅读-------------

本文标题:duubo的proxy代理

文章作者:夸克

发布时间:2020年06月21日 - 16:06

最后更新:2022年07月01日 - 06:07

原始链接:https://zhanglijun1217.github.io/2020/06/21/duubo的proxy代理/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。