Dubbo实践(十)代理
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实践(十)代理的更多相关文章
- 曹工说mini-dubbo(1)--为了实践动态代理,我写了个简单的rpc框架
相关背景及资源: 之前本来一直在写spring源码解析这块,如下,aop部分刚好写完.以前零散看过一些文章,知道rpc调用基本就是使用动态代理,比如rmi,dubbo,feign调用等.自己也就想着试 ...
- Dubbo实践(六)Spring加载Bean流程
根据上一小节对于spring扩展schema的介绍,大概可以猜到dubbo中相关的内容是如何实现的. 再来回顾Dubbo实践(一)中定义的dubbo-provider.xml: <?xml ve ...
- Dubbo实践(五)扩展Spring Schema
先回顾Dubbo实践(一)中定义的dubbo-provider.xml: <?xml version="1.0" encoding="UTF-8"?> ...
- Dubbo实践(十五)消费者引用服务
Refer取得invoker的过程 <!-- 指定了哪种的注册中心,是基于zookeeper协议的,指定了注册中心的地址以及端口号 --> <dubbo:registry proto ...
- Dubbo实践(十四)生产者发布服务
Export发布服务流程 Dubbo协议向注册中心发布服务:当服务提供方,向dubbo协议的注册中心发布服务的时候,是如何获取,创建注册中心的,如何注册以及订阅服务的,下面我们来分析其流程. 看如下配 ...
- Dubbo实践(十二)Refer
Spring在启动Dubbo客户端应用时,会实例化ReferenceBean<T>并设置配置属性,然后调用ReferenceConfig中的get方法: public synchroniz ...
- Dubbo实践(十六)集群容错
Dubbo作为一个分布式的服务治理框架,提供了集群部署,路由,软负载均衡及容错机制.下图描述了Dubbo调用过程中的对于集群,负载等的调用关系: 集群 Cluster 将Directory中的多个In ...
- Dubbo实践(三)框架设计
整体设计 图例说明: 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口: 图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层 ...
- 阿里技术专家详解 Dubbo 实践,演进及未来规划
Dubbo 整体介绍 Dubbo 是一款高性能,轻量级的 Java RPC 框架.虽然它是以 Java 语言来出名的,但是现在我们生态里面已经有 Go.Python.PHP.Node.JS 等等语言. ...
随机推荐
- yum只下载不安装dokcer
yum install --downloadonly --downloaddir=/test/ docker-io 有三个依赖包,如果不知道现后依赖顺序,可以强制安装 哦了
- 【C++并发实战】(一)并发基本概念
什么是并发 并发,最简单的理解就是,两个或者以上的活动同时进行.举个比较实际的例子,你可以手脚并用,两只手做不同的动作等等. 在计算机中的“并发”,是指一个系统可以同时执行多个独立的活动.在以前大多数 ...
- js事件队列
前面跟网友讨论到了JS的事件队列 ,对这个有了一些理解,事件队列我认为就是把一些不按顺序执行的事件放到队列里面,然后按照自己制定的顺序去执行,那么什么情况下会用到这个呢?我首先想到的是动画,动画是会执 ...
- border实现三角形的原理
前言:网上最普遍的实现三角形的方法,就是通过控制border来实现,那为什么可以呢? 原理 我们先来看看border的表现形式. #box{ width:100px; height:100px; ba ...
- Javascript周报#182
This week’s JavaScript news Read this issue on the Web | Issue Archive JavaScript Weekly Issue 182Ma ...
- C# 按部门拆分excel文件
按照所属部门不同将excel文件拆分成多个文件 string excel_path = @"G:\zhyue\backup\2018-08-01 读取腾讯邮箱接口-获取一个月内未接收到外部邮 ...
- LeetCode赛题394----Decode String
394. Decode String Given an encoded string, return it's decoded string. The encoding rule is: k[enco ...
- 关于modelmap.addAttribute("",)转到jsp页面获取不到值的问题
问题一,可能是你设置的web.xml的头有问题 掉坑里好一会,发现我默认生成的web.xml中头部的配置是 <!DOCTYPE web-app PUBLIC "-//Sun Micro ...
- html5 移动端开发
移动端开发总结 目录 1.手机与浏览器 2.Viewport(视窗) 3. 媒体查询 4.px,em,rem,pt 5.设备像素比devicePixelRatio 6.移动web中的图标及字体 ...
- Hadoop & Spark & Hive & HBase
Hadoop: http://hadoop.apache.org/docs/r2.6.4/hadoop-project-dist/hadoop-common/SingleCluster.html bi ...