com.alibaba.dubbo.common.bytecode.Proxy利用字节码技术来创建对象源码分析

半兽人 发表于: 2018-01-11   最后更新时间: 2018-01-11 19:34:48  
{{totalSubscript}} 订阅, 8,501 游览
public <T> T getProxy(Invoker<T> invoker,Class<?>[] interfaces) {
       return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}

看似跟jdk生成代理一样, 其实这里的Proxy类不是jdk中自带那个生成代理对象的类是:

com.alibaba.dubbo.common.bytecode.Proxy

这个dubbo自己写的Proxy类,利用要代理的接口利用javassist工具生成代理代码。

获取Invoker 对象

public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {

    final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);

    return new AbstractProxyInvoker<T>(proxy, type, url) {

        protected Object doInvoke(T proxy, String methodName, 
                Class<?>[] parameterTypes, Object[] arguments) throws Throwable {

            return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
        }
    };
}

根据传入的 proxy对象 的类信息创建对它的包装对象Wrapper返回Invoker对象实例, 这个invoker对象invoke方法可以根据传入的invocation对象中包含的方法名,

方法参数来调用proxy对象返回调用结果

com.alibaba.dubbo.common.bytecode.Proxy 生成代理对象的工具类

  1. 遍历所有入参接口,以;分割连接起来, 以它为key以map为缓存查找如果有,说明代理对象已创建返回

  2. 利用AtomicLong对象自增获取一个long数组来作为生产类的后缀,防止冲突

  3. 遍历接口获取所有定义的方法,加入到一个集合Set worked中,用来判重,

    获取方法y应该在methods数组中的索引下标ix

    获取方法的参数类型以及返回类型

    构建方法体return ret= handler.invoke(this, methods[ix], args);

    这里的方法调用其实是委托给InvokerInvocationHandler实例对象的,去调用真正的实例方法加入到methods数组中。

  4. 创建代理实例对象ProxyInstance

    类名为 pkg + “.poxy”+id = 包名 + “.poxy” +自增数值

    添加静态字段Method[] methods;

    添加实例对象InvokerInvocationHandler hanler

    添加构造器参数是InvokerInvocationHandler

    添加无参构造器

    利用工具类ClassGenerator生成对应的字节码

  5. 创建代理对象,它的newInstance(handler)方法用来创建基于我们接口的代理
    代理对象名Proxy + id

     // create Proxy class.
     String fcn = Proxy.class.getName() + id;
     ccm = ClassGenerator.newInstance(cl);
     ccm.setClassName(fcn);
     ccm.addDefaultConstructor();
     ccm.setSuperClass(Proxy.class);
     ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn +      "($1); }");
     Class<?> pc = ccm.toClass();
     proxy = (Proxy)pc.newInstance();
    

    继承于Proxy, 所以要实现newInstance方法

    添加默认构造器

    实现方法newInstance代码, new pcn(hadler) 这里pcn就是前面生成的代理对象类名

    利用工具类ClassGenerator生成字节码并实例化对象返回

更新于 2018-01-11
在线,1小时前登录

Joyven 5年前

看的不是很懂呀

查看dubbo更多相关的文章或提一个关于dubbo的问题,也可以与我们一起分享文章