博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Dubbo之ProxyFactory
阅读量:7069 次
发布时间:2019-06-28

本文共 5021 字,大约阅读时间需要 16 分钟。

  hot3.png

概述

在分析服务暴露和服务引用的都提到ProxyFactory,它是Dubbo的代理工厂,只定义了两个方法。

  • getInvoker,暴露服务时调用,将ref(真正的服务实现类)转化为Invoker
  • getProxy,引用服务时调用,将Invoker对象转化为proxy代理对象

Invoker

Invoker 是 Dubbo 领域模型中非常重要的一个概念,很多设计思路都是向它靠拢。这就使得 Invoker 渗透在整个实现代码里,对于刚开始接触 Dubbo 的人,确实容易给搞混了。 下面我们用一个精简的图来说明最重要的两种 Invoker:服务提供 Invoker 和服务消费 Invoker:

上面是出自Dubbo的官方教程。

服务提供端的AbstractProxyInvoker,封装了真正的服务实现类,代理了它的方法。服务消费端的DubboInvoker等,封装了远程通信的逻辑。

Dubbo中对远程的调用是Invoker,调用服务真正的实现类也是Invoker。

ProxyFactory

Dubbo的代理工厂,Dubbo之所以能够宣传像调用本地服务一样调用远程服务,就是用它实现的。@SPI扩展接口,默认实现是JavassistProxyFactory,还有一个实现是JdkProxyFactory,最终都会被StubProxyFactoryWrapper包装。

@SPI("javassist")public interface ProxyFactory {    /**     * 服务引用时调用     * create proxy.     *     * @param invoker   Protocol生成的Invoker     * @return proxy     */    @Adaptive({Constants.PROXY_KEY})    
T getProxy(Invoker
invoker) throws RpcException; /** * 服务暴露时调用 * create invoker. * * @param
* @param proxy Service对象 * @param type Service类型 * @param url * @return invoker */ @Adaptive({Constants.PROXY_KEY})
Invoker
getInvoker(T proxy, Class
type, URL url) throws RpcException;}

getInvoker

JavassistProxyFactory和JdkProxyFactory的返回的都是AbstractProxyInvoker,区别在于前者使用自动生成的类,包装了硬编码进行调用,后者则使用JDK反射机制进行调用。对于Dubbo来说都是Invoker,进行了统一的抽象,这样Dubbo框架就不需要关心服务的具体业务,全部交给AbstractProxyInvoker去封装。

真正调用服务的时候会执行Invoker#invoke(),而AbstractProxyInvoker会把调用转给真正的服务实现类。

JavassistProxyFactory

public 
Invoker
getInvoker(T proxy, Class
type, URL url) { // TODO Wrapper类不能正确处理带$的类名 // TODO Wrapper cannot handle this scenario correctly: the classname contains '$' // proxy.getClass()返回的是实现类的Class,type是接口的Class // Wrapper对象对方法的调用进行了包装,没有使用反射, // Wrapper是使用javassist动态生成类才进行方法调用的包装 final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); return new AbstractProxyInvoker
(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class
[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } };}

某个Wrapper类的代码片段,没有用反射

public Object invokeMethod(Object var1, String var2, Class[] var3, Object[] var4) throws InvocationTargetException {    DemoService var5;    try {        var5 = (DemoService)var1;    } catch (Throwable var8) {        throw new IllegalArgumentException(var8);    }    try {        if ("sayHello".equals(var2) && var3.length == 1) {            return var5.sayHello((String)var4[0]);        }    } catch (Throwable var9) {        throw new InvocationTargetException(var9);    }    throw new NoSuchMethodException("Not found method \"" + var2 + "\" in class cre.dubbo.demo.DemoService.");}

JdkProxyFactory

public 
Invoker
getInvoker(T proxy, Class
type, URL url) { return new AbstractProxyInvoker
(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); } };}

getProxy

生成的代理类实现指定的服务接口(还会实现EchoService接口),因此消费端在使用代理对象的时候跟使用本地服务是一样的。JavassistProxyFactory和JdkProxyFactory的都使用到了InvokerInvocationHandler

InvokerInvocationHandler它的作用是将消费端的调用转到内部的Invoker#invoke()上

JavassistProxyFactory

public 
T getProxy(Invoker
invoker, Class
[] interfaces) { return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));}

JdkProxyFactory

public 
T getProxy(Invoker
invoker, Class
[] interfaces) { return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));}

InvokerInvocationHandler

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]); } // Invoker进行Rpc调用 return invoker.invoke(new RpcInvocation(method, args)).recreate();}

附录

参照:

转载于:https://my.oschina.net/cregu/blog/2223351

你可能感兴趣的文章
Python 字符串常用方法
查看>>
Android Could not find com.afollestad:material-dialogs:0.7.6.0 解决
查看>>
构造定律(constructal law)-构造定律作为第二个时间箭头,将和热力学第二定律一道将宇宙推向无序。...
查看>>
八大免费SSL证书-给你的网站免费添加Https安全加密
查看>>
虚拟机安装苹果系统 出现不可恢复的错误解决办法
查看>>
Cocos2d中的Menu使用
查看>>
PHP中include()与require()的区别说明
查看>>
Mybatis之基于XML的调用存储过程与手动回滚事务
查看>>
csrf攻击
查看>>
hexo从零开始到搭建完整 转
查看>>
HDUOJ Metric Time
查看>>
让C#事件也可以异步触发
查看>>
读《打造FaceBook》
查看>>
CodeIgniter笔记
查看>>
mybatis.net - 4 ISqlMapper 传递参数
查看>>
【分享】这些年,我使用的一些工具[非开发类]
查看>>
nullnullanimate用法
查看>>
如何让Ubuntu 12.04 LTS更炫更具吸引力
查看>>
VC获取精确时间的做法
查看>>
10 个超炫绘制图表图形的 Javascript 插件【转载+整理】
查看>>