dubbo为consumer创建代理
ReferenceConfig.init()方法中获取到了最终的代理对象,先观察一下代理对象的视图。
默认使用javassist生成动态类,可配置proxy为jdk,则使用jdk动态代理:
<dubbo:reference id="hello" interface="com.zhang.HelloService" proxy="jdk" merger="true" check="false"/>
jdk代理对象视图如下图:
RegistryDirectory中有一个 urlInvokerMap。
// Map<url, Invoker> cache service url to invoker mapping.
private volatile Map<String, Invoker<T>> urlInvokerMap;
示例:
键: dubbo://192.168.233.6:20880/com.zhang.HelloService?anyhost=true&application=consumerk_app&check=false&dubbo=2.5.2&group=a&interface=com.zhang.HelloService&iothreads=2&merger=true&methods=sayHello,sayException,sayHi,sayFuck&pid=6736&sayException.retries=0&sayFuck.retries=0&sayFuck.return=true&sayHello.retries=0&sayHi.retries=0&side=consumer&timeout=6000×tamp=1516256748120
值: com.alibaba.dubbo.registry.integration.RegistryDirectory$InvokerDelegete@4147e2b6
然后分析代理的创建过程,主要的调用栈如下:
贴出Protocol$Adpative的代码:
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException(
"method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
} public int getDefaultPort() {
throw new UnsupportedOperationException(
"method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
} public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0,
com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
if (arg1 == null)
throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
//url不同,获得的扩展名是不一样的
String extName = (url.getProtocol() == null ? "dubbo" : url
.getProtocol());
if (extName == null)
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url("
+ url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader
.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class)
.getExtension(extName);
return extension.refer(arg0, arg1);
} public com.alibaba.dubbo.rpc.Exporter export(
com.alibaba.dubbo.rpc.Invoker arg0)
throws com.alibaba.dubbo.rpc.Invoker {
if (arg0 == null)
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = (url.getProtocol() == null ? "dubbo" : url
.getProtocol());
if (extName == null)
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url("
+ url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader
.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class)
.getExtension(extName);
return extension.export(arg0);
}
}
从调用栈可以看到,Protocol\$Adpative.refer(Class, URL)调用了2次。但是传递的URL参数是不一样的,
第一次获取的protocol是 ProtocolFilterWrapper/ProtocolListenerWrapper/RegistryProtocol,
第二次获取的protocol是 ProtocolFilterWrapper/ProtocolListenerWrapper/DubboProtocol。
所以在ProtocolListenerWrapper和ProtocolFilterWrapper中走的分支不同。
(第一次的URL是:
registry://192.168.153.1:2181/com.alibaba.dubbo.registry.RegistryService?application=consumer&dubbo=2.1.2&localhost=true&pid=2504&refer=application%3Dconsumer%26dubbo%3D2.1.2%26interface%3Dcom.zhang.HelloService%26methods%3DsayHello%26pid%3D2504%26timestamp%3D1516461886484®istry=zookeeper×tamp=1516461886531
Protocol$Adpative.refer的refer方法中,getExtension()返回的扩展是ProtocolListenerWrapper/ProtocolFilterWrapper/RegistryProtocol。
第二次的URL是:
dubbo://192.168.153.1:20880/com.zhang.HelloService?anyhost=true&application=consumer&check=false&dubbo=2.1.2&interface=com.zhang.HelloService&methods=sayHello&pid=2504×tamp=1516461886484)
//ProtocolListenerWrapper类
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
//先进这个分支
return protocol.refer(type, url);
}
//后续再进这个分支
return new ListenerInvokerWrapper<T>(protocol.refer(type, url),
Collections.unmodifiableList(
ExtensionLoader.getExtensionLoader(InvokerListener.class)
.getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
} //ProtocolFilterWrapper类
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
//先进这个分支
return protocol.refer(type, url);
}
//后续再进这个分支
return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
}
ReferenceConfig<T>的createProxy方法负责创建代理,分析之后得到的步骤大致如下:
1. 生成invoker
// ReferenceConfig.createProxy方法。refprotocol是Protocol$Adpative对象
invoker = refprotocol.refer(interfaceClass, url);
1.1 生成filter链(使用内部类把filter和next封装起来。相当于创建一个类,有Filter属性,和Invoker属性)
//ProtocolFilterWrapper类
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
// ConsumerContextFilter, MonitorFilter, FutureFilter
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i --) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
public Class<T> getInterface() {
return invoker.getInterface();
}
public URL getUrl() {
return invoker.getUrl();
}
public boolean isAvailable() {
return invoker.isAvailable();
}
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
1.2 生成RegistryDirectory$InvokerDelegete对象
// RegistryDirectory.toInvokers
// protocol.refer(serviceType, url)就是调用Protocol$Adpative的refer方法,即递归调用
invoker = new InvokerDelegete<T>(protocol.refer(serviceType, url), url, providerUrl);
1.3 生成MockClusterInvoker。涉及2个类:Protocol$Adpative和Cluster$Adpative,调用栈如下,
package com.alibaba.dubbo.rpc.cluster;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Cluster$Adpative implements com.alibaba.dubbo.rpc.cluster.Cluster {
public com.alibaba.dubbo.rpc.Invoker join(
com.alibaba.dubbo.rpc.cluster.Directory arg0)
throws com.alibaba.dubbo.rpc.cluster.Directory {
if (arg0 == null)
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.cluster.Directory argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.cluster.Directory argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("cluster", "failover");
if (extName == null)
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.cluster.Cluster) name from url("
+ url.toString() + ") use keys([cluster])");
com.alibaba.dubbo.rpc.cluster.Cluster extension = (com.alibaba.dubbo.rpc.cluster.Cluster) ExtensionLoader
.getExtensionLoader(com.alibaba.dubbo.rpc.cluster.Cluster.class)
.getExtension(extName);
// extension是MockClusterWrapper
return extension.join(arg0);
}
}
2. 创建代理。
private static final ProxyFactory proxyFactory =
ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
private T createProxy(Map<String, String> map) {
// 省略其他代码
return (T) proxyFactory.getProxy(invoker);
}
/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.ProxyFactory文件内容:
stub=com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper
jdk=com.alibaba.dubbo.rpc.proxy.jdk.JdkProxyFactory
javassist=com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory
可以看到上面有一个wrapper,所以调用getExtension方法获得的扩展是StubProxyFactoryWrapper。
动态生成的ProxyFactory$Adpative类代码,格式化如下:
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class ProxyFactory$Adpative implements com.alibaba.dubbo.rpc.ProxyFactory {
public java.lang.Object getProxy(com.alibaba.dubbo.rpc.Invoker arg0)
throws com.alibaba.dubbo.rpc.Invoker {
if (arg0 == null)
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if (extName == null)
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url("
+ url.toString() + ") use keys([proxy])");
com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader
.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class)
.getExtension(extName);
// extension其实是StubProxyFactoryWrapper对象,对JavassistProxyFactory做一个wrap
return extension.getProxy(arg0);
} public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0,
java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2)
throws java.lang.Object {
if (arg2 == null)
throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg2;
String extName = url.getParameter("proxy", "javassist");
if (extName == null)
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url("
+ url.toString() + ") use keys([proxy])");
com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader
.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class)
.getExtension(extName);
return extension.getInvoker(arg0, arg1, arg2);
}
}
所以getExtension的返回对象是:StubProxyFactoryWrapper/JavassistProxyFactory
// JavassistProxyFactory
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
//一、 Proxy p = Proxy.getProxy(interfaces);
//二、 p.newInstance(new InvokerInvocationHandler(invoker));
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
Proxy0和proxy0是javassist动态生成的类:其中p是Proxy0实例,调用newInstance(InvocationHandler)方法创建proxy0实例。
下面是推测的代码(大概):
class com.alibaba.dubbo.common.bytecode.Proxy0 extends com.alibaba.dubbo.common.bytecode.Proxy {
public Object newInstance(java.lang.reflect.InvocationHandler h){
return new com.alibaba.dubbo.common.bytecode.proxy0($1);
}
} class com.alibaba.dubbo.common.bytecode.proxy0 implements
com.alibaba.dubbo.rpc.service.EchoService, com.zhang.HelloService {
public <init>(java.lang.reflect.InvocationHandler arg0){
handler=$1;
}
public static java.lang.reflect.Method[] methods;
private java.lang.reflect.InvocationHandler handler; public java.lang.String sayHello(){
Object[] args = new Object[0];
Object ret = handler.invoke(this, methods[0], args);
return (java.lang.String)ret;
}
public java.lang.Object $echo(java.lang.Object arg0){
Object[] args = new Object[1];
args[0] = ($w)$1;
Object ret = handler.invoke(this, methods[1], args);
return (java.lang.Object)ret;
}
}
dubbo为consumer创建代理的更多相关文章
- 161130、Dubbo+SpringMVC工程创建详解
Dubbo出现的目的是为了应对现在高并发,高数据量请求的问题.目前的垂直应用架构已经无法满足现在大数据的冲击,SOA就应运而生,而Dubbo在国内使用的还是比较多,稳定性也比较不错. 架构 节点角色说 ...
- Dubbo原理实现之代理接口的定义
Dubbo有很多的实现采用了代码模式,Dubbo由代理工厂ProxyFactory对象创建代理对象. ProxyFactory接口的定义如下: @SPI("javassist") ...
- Entity Framework 6 Recipes 2nd Edition(13-10)译 -> 显式创建代理
问题 你有一个POCO实体,原本在执行一个查询时动态创建代理,现在你不想EF延迟创建代理带来的代价. 解决方案 假设你有一个如图Figure13-15的模型 Figure 13-15. A model ...
- SQL Server Alwayson创建代理作业注意事项
介绍 Always On 可用性组活动辅助功能包括支持在辅助副本上执行备份操作. 备份操作可能会给 I/O 和 CPU 带来很大的压力(使用备份压缩). 将备份负荷转移到已同步或正在同步的辅助副本后, ...
- Spring AOP 自动创建代理
Spring为我们提供了自动代理机制,让容器为我们自动生成代理,把我们从烦琐的配置工作中解放出来,在内部,Spring 使用BeanPostProcessor自动地完成这项工作. 1.实现 ...
- Spring AOP 源码分析 - 创建代理对象
1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...
- 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-使用工厂创建代理(Using the ProxyFactoryObject to create AOP proxies)
本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 如果你正在为你的业务模型使用 ...
- Spring Aop(十四)——Aop自动创建代理对象的原理
转发地址:https://www.iteye.com/blog/elim-2398725 Aop自动创建代理对象的原理 我们在使用Spring Aop时,通常Spring会自动为我们创建目标bean的 ...
- Spring Aop(十三)——ProxyFactoryBean创建代理对象
转发地址:https://www.iteye.com/blog/elim-2398673 ProxyFactoryBean创建代理对象 ProxyFactoryBean实现了Spring的Factor ...
随机推荐
- Jsp获取Java的对象(JavaBean)
Jsp获取Java的对象(JavaBean) Java代码片段: AuthReqBean authRep=new AuthReqBean(); authRep.setUserCode(usercode ...
- python 线程 进程 协程 学习
转载自大神博客:http://www.cnblogs.com/aylin/p/5601969.html 仅供学习使用···· python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和 ...
- exp9《网络对抗》web安全基础实践201453331魏澍琛
201453331魏澍琛web安全基础实践 一.实验过程 1.webgoat开启 2.Injection Flaws练习 Command Injection 原网页中没有注入的地方,那就用burpsu ...
- C# 获取枚举的描述属性
在使用枚举类型时,我们需要取名称和值,甚至有时候还需要取枚举类型的描述.通过反射,我们能获取到枚举类型的描述属性. 首先我们需要给枚举类型添加描述属性(属性都没有是不可能取到的),[Descripti ...
- C# 图片和64位编码的转换
/* 将图片转换为64位编码 */ //找到文件夹 System.IO.DirectoryInfo dd = new System.IO.DirectoryInfo("C://qq" ...
- 【angular2+typeScript+ng-zorro】Carousel 走马灯的左右方向控件实现
ng-zorro Carousel 走马灯的左右方向控件实现 ng-zorro框架的走马灯本身还没有左右方向控件的实现,作者只是在文档中(0.6x)中曝出几个方法接口,如图: 实现: 在根compon ...
- mips32和x86下的大小端模式判定
一.背景 1.1 mips32搭载32bit vxworks操作系统 1.2 x86搭载64bit windows10操作系统 二.大小端模式判定前的准备 2.1 先要知道各种架构上各种整型数占据的b ...
- PHP获取当前页面的网址
PHP获取当前页面的网址 function GetCurUrl() { $url = 'http://'; if(isset($_SERVER['HTTPS']) AND $_SERVER['HTTP ...
- Win7上安装WMware虚拟机和Ubuntu操作系统
效果图: 问题拾遗: 一.如何划分一个新硬盘空间? 参考链接:如何新建磁盘空间 效果图: 我划分了20G的内存空间给Ubuntu的硬盘空间.一般来说15G就够用了. 二.VMware上拷贝Ubuntu ...
- UVa 1606 两亲性分子
https://vjudge.net/problem/UVA-1606 题意:平面上有n个点,每个点为白点或者黑点.现在需放置一条隔板,使得隔板一侧的白点数加上另一侧的黑点数总数最大.隔板上的点可以看 ...