Invoker调用

代理有几种方式:普通代理、JDK、Javassist库动态代理、Javassist库动态字节码代理。

生成代理的目的是你调用invoker的相关函数后,就等同于是调用DubboInvoker中的相关函数,也就是将本地调用转为网络调用并获得结果。

// create service proxy
return (T) proxyFactory.getProxy(invoker);
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
/**
* ProxyFactory. (API/SPI, Singleton, ThreadSafe)
*/
@SPI("javassist")
public interface ProxyFactory { /**
* create proxy.
*
* @param invoker
* @return proxy
*/
@Adaptive({Constants.PROXY_KEY})
<T> T getProxy(Invoker<T> invoker) throws RpcException; /**
* create invoker.
*
* @param <T>
* @param proxy
* @param type
* @param url
* @return invoker
*/
@Adaptive({Constants.PROXY_KEY})
<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException; }

Dubbo提供了三种代理工厂,默认的代理工厂是JavassistProxyFactory

/**
* JavaassistRpcProxyFactory
*/
public class JavassistProxyFactory extends AbstractProxyFactory { @SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
} public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
} }

getProxy方法中实例化了InvokerInvocationHandler类,该类封装了代理是如何工作的:

/**
* InvokerHandler
*/
public class InvokerInvocationHandler implements InvocationHandler { private final Invoker<?> invoker; public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
} 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]);
}
return invoker.invoke(new RpcInvocation(method, args)).recreate();
} }

此时我们在DubboInvoker.java类中可以看到invoke函数中最终会调用doInvoke函数,此时转为网络调用。

这里我们通过RpcInvocation对象,可以确认客户端传递给invoker的信息:

public RpcInvocation(Invocation invocation, Invoker<?> invoker) {
this(invocation.getMethodName(), invocation.getParameterTypes(),
invocation.getArguments(), new HashMap<String, String>(invocation.getAttachments()),
invocation.getInvoker());
if (invoker != null) {
URL url = invoker.getUrl();
setAttachment(Constants.PATH_KEY, url.getPath());
if (url.hasParameter(Constants.INTERFACE_KEY)) {
setAttachment(Constants.INTERFACE_KEY, url.getParameter(Constants.INTERFACE_KEY));
}
if (url.hasParameter(Constants.GROUP_KEY)) {
setAttachment(Constants.GROUP_KEY, url.getParameter(Constants.GROUP_KEY));
}
if (url.hasParameter(Constants.VERSION_KEY)) {
setAttachment(Constants.VERSION_KEY, url.getParameter(Constants.VERSION_KEY, "0.0.0"));
}
if (url.hasParameter(Constants.TIMEOUT_KEY)) {
setAttachment(Constants.TIMEOUT_KEY, url.getParameter(Constants.TIMEOUT_KEY));
}
if (url.hasParameter(Constants.TOKEN_KEY)) {
setAttachment(Constants.TOKEN_KEY, url.getParameter(Constants.TOKEN_KEY));
}
if (url.hasParameter(Constants.APPLICATION_KEY)) {
setAttachment(Constants.APPLICATION_KEY, url.getParameter(Constants.APPLICATION_KEY));
}
}
}

JDK代理

这里实际上只是根据JDK代理机制来生成相应的代理

/**
* JavaassistRpcProxyFactory
*/
public class JdkProxyFactory extends AbstractProxyFactory { @SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
} public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
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);
}
};
} }

Dubbo实践(十)代理的更多相关文章

  1. 曹工说mini-dubbo(1)--为了实践动态代理,我写了个简单的rpc框架

    相关背景及资源: 之前本来一直在写spring源码解析这块,如下,aop部分刚好写完.以前零散看过一些文章,知道rpc调用基本就是使用动态代理,比如rmi,dubbo,feign调用等.自己也就想着试 ...

  2. Dubbo实践(六)Spring加载Bean流程

    根据上一小节对于spring扩展schema的介绍,大概可以猜到dubbo中相关的内容是如何实现的. 再来回顾Dubbo实践(一)中定义的dubbo-provider.xml: <?xml ve ...

  3. Dubbo实践(五)扩展Spring Schema

    先回顾Dubbo实践(一)中定义的dubbo-provider.xml: <?xml version="1.0" encoding="UTF-8"?> ...

  4. Dubbo实践(十五)消费者引用服务

    Refer取得invoker的过程 <!-- 指定了哪种的注册中心,是基于zookeeper协议的,指定了注册中心的地址以及端口号 --> <dubbo:registry proto ...

  5. Dubbo实践(十四)生产者发布服务

    Export发布服务流程 Dubbo协议向注册中心发布服务:当服务提供方,向dubbo协议的注册中心发布服务的时候,是如何获取,创建注册中心的,如何注册以及订阅服务的,下面我们来分析其流程. 看如下配 ...

  6. Dubbo实践(十二)Refer

    Spring在启动Dubbo客户端应用时,会实例化ReferenceBean<T>并设置配置属性,然后调用ReferenceConfig中的get方法: public synchroniz ...

  7. Dubbo实践(十六)集群容错

    Dubbo作为一个分布式的服务治理框架,提供了集群部署,路由,软负载均衡及容错机制.下图描述了Dubbo调用过程中的对于集群,负载等的调用关系: 集群 Cluster 将Directory中的多个In ...

  8. Dubbo实践(三)框架设计

    整体设计 图例说明: 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口: 图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层 ...

  9. 阿里技术专家详解 Dubbo 实践,演进及未来规划

    Dubbo 整体介绍 Dubbo 是一款高性能,轻量级的 Java RPC 框架.虽然它是以 Java 语言来出名的,但是现在我们生态里面已经有 Go.Python.PHP.Node.JS 等等语言. ...

随机推荐

  1. Java 集合:List(ArrayList,LinkedList)

  2. Bash拾遗:变量

    使用引号包裹变量 在<高级Bash脚本编程指南>中的4.1节中有这么个例子: hello="A B C D" echo $hello # A B C D echo &q ...

  3. TopCoder14580: EllysRPS

    题意 \(yyb\)要去与\(m\)\((m\le100)\)个人玩游戏 由于\(yyb\)忙着切大火题,他没有太多的精力浪费在游戏上 所以仁慈的\(yyb\)决定放\(m\)个人一条生路,不吊打他们 ...

  4. C# 读取config

    控制台应用程序 App.config: AppSettings.config: Program.cs: string a = ConfigurationManager.AppSettings[&quo ...

  5. CentOS 7 Apache 多端口部署 Web Apps 指南

    转载自简书,原作者xuyan0,链接https://www.jianshu.com/p/b34c78bf9bf0,如有侵权,请联系删除 导语 Apache web 服务器运行着互联网上超过半数的活跃的 ...

  6. centos下安装ipython(minglnghang命令行)

    下载文件 wget https://bootstrap.pypa.io/get-pip.py --no-check-certificate 执行安装 python get-pip.py 这就安装好了 ...

  7. mvn install 时候报GBK编码错误解决办法

    在pom.xml里面 <properties> <!-- 文件拷贝时的编码 --> <project.build.sourceEncoding>UTF-</p ...

  8. js时间戳转换日期

    //js时间戳转换日期function formatDate(now) { var year=now.getFullYear(); var month=now.getMonth()+1; var da ...

  9. Java容器之HashMap源码分析

    在java的容器框架中,hashMap是最常用的容器之一,下面我们就来深入了解下它的数据结构和实现原理 先看下HashMap的继承结构图 下面针对各个实现类的特点进行下说明:1)HashMap: 它是 ...

  10. Docker-commit镜像提交

    docker commit:提交容器副本使之成为一个新的镜像 docker commit -a="作者名" -m="提交的描述信息" 容器id 新建的镜像名称: ...