首页 > 编程语言 >Dubbo源码-06-ProxyFactory

Dubbo源码-06-ProxyFactory

时间:2022-11-25 16:57:08浏览次数:52  
标签:Dubbo 06 dubbo alibaba rpc 源码 proxy com Invoker

作用

  • 生产者将要导出的目标对象封装(代理技术或者反射技术)成Invoker对象

一 接口

@SPI("javassist")
public interface ProxyFactory {

    /**
     * create proxy.
     *
     * @param invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    /**
     * create proxy.
     *
     * @param invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;

    /**
     * create invoker.
     *
     * @param <T>
     * @param proxy
     * @param type
     * @param url
     * @return invoker
     */
    /**
     * 生产者调用这个方法生成Invoker对象
     * 将来某个时机通过Invoker对象执行invoke(...)方法 使用到目标对象提供的方法
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

}

首先@SPI指定扩展默认名称javassist

其次getInvoker(...)方法上注解@Adaptive标识了编码生成自适应类对象使用URL中配置项是proxy

2 配置文件

stub=com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper
jdk=com.alibaba.dubbo.rpc.proxy.jdk.JdkProxyFactory
javassist=com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory

实现类没有被@Adaptive标识的

3 通过生成code方式创建自适应扩展实现类对象

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.extension.ExtensionLoader;

public class ProxyFactory$Adaptive implements com.alibaba.dubbo.rpc.ProxyFactory {

    public java.lang.Object getProxy(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
        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);
        return extension.getProxy(arg0);
    }

    public java.lang.Object getProxy(com.alibaba.dubbo.rpc.Invoker arg0, boolean arg1) throws com.alibaba.dubbo.rpc.RpcException {
        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);
        return extension.getProxy(arg0, arg1);
    }

    public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws com.alibaba.dubbo.rpc.RpcException {
        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);
    }
}

4 最终实现

运行时根据形参URL中proxy情况而定

  • 默认javassist
  • URL中配置项proxy

4.1 JavassistProxyFactory

public class JavassistProxyFactory extends AbstractProxyFactory {

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        /**
         * Proxy.getProxy()通过字节码技术生成了一个代理对象 暴露了一个newInstance()的方法 维护了一个InvocationHandler的属性
         * 因此这个地方一定是像代理对象中赋值了InvocationHandler属性
         * 后续调用该代理对象的方法是 实际是委托给了InvocationHandler进行处理
         */
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

    @Override
    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);
        // 匿名内部类 将来Invoker实例的invoker(...)方法会调用到doInvoke(...)
        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); // 通过代理对象执行目标对象的方法
            }
        };
    }

}

4.2 JdkProxyFactory

public class JdkProxyFactory extends AbstractProxyFactory {

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
    }

    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // 将来通过Invoker对象调用invoke(...)时调用内部类的doInvoke(...)方法
        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); // Java反射调用目标对象的方法
                return method.invoke(proxy, arguments);
            }
        };
    }

}

标签:Dubbo,06,dubbo,alibaba,rpc,源码,proxy,com,Invoker
From: https://www.cnblogs.com/miss-u/p/16925664.html

相关文章

  • Dubbo源码-07-Protocol
    作用生产者将Invoker对象导出InjvmProtocol没有真正的干活逻辑仅仅是一些属性赋值DubboProtol启动服务RegistryProtol通过DubboProtocol启动服务注册远程配置......
  • SpringBoot原理深入及源码剖析
    1依赖管理问题:(1)为什么导入dependency时不需要指定版本?在SpringBoot入门程序中,项目pom.xml文件有两个核心依赖,分别是spring-boot-starter-parent和spring-boot-starter-w......
  • Dubbo 动态配置中心
    ##前言大家好,今天开始给大家分享—Dubbo专题之Dubbo动态配置中心。在前一个章节中我们介绍了Dubbo中的注册中心以及多种不同的注册中心实现,我们在这个章节会介绍Du......
  • 4-4 child_process 库源码分析
    疑问和收获exec和execFile到底有什么区别?为什么exec/execFile/fork都是通过spawn实现的,spawn的作用到底是什么?为什么spawn调用后没有回调,而exec和......
  • matlab工具箱TTSBOX源码中文分析
    functionwav=tts(txt,voice,pace,fs)%TTStexttospeech.%TTS(TXT)synthesizesspeechfromstringTXT,andspeaksit.Theaudio%formatismono,16bit,1......
  • 【iOS-Cocos2d游戏开发之十五】详解CCProgressTimer 进度条并修改cocos2d源码实现“理
    ​​ 李华明Himi ​​​原创,转载务必在明显处注明     游戏开发中难免用到进度条,例如做一些游戏技能的CD时间等都会使用到;那么cocos2d当然也封装了进度条,但是不......
  • 手机直播源码,flutter 随机数的生成和保留两位小数
    手机直播源码,flutter随机数的生成和保留两位小数一、生成最小值和最大值之间的随机数使用Random().nextInt()方法,生成一个整数 random(min,max){ //+min 表......
  • 1006. Sign In and Sign Out (25)
    1006.SignInandSignOut(25)时间限制400ms内存限制65536kB代码长度限制16000B判题程序......
  • 视频直播系统源码,flutter Wrap 自动换行组件
    视频直播系统源码,flutterWrap自动换行组件 先来简单的看一下源码 Wrap({  super.key,  this.direction=Axis.horizontal,  this.alignment=WrapAl......
  • Scrapy爬虫框架,入门案例(非常详细)源码
    一、概述Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试.......