Dubbo源码分析之JavassistProxy代理---(十四)

265 阅读3分钟

本源码主要是基于2.7.7-release版本. Dubbo中代理的扩展点是ProxyFactory接口,默认SPI扩展点是 javassist, 是通过Proxy#getProxy方案,传入接口,然后调用newInstance 创建动态代理,这里Proxy是Dubbo实现的代理抽象类,并不是jdk的原生的Proxy,但是这列InvokerInvocationHandler还是实现JDK原生的InvocationHandler接口. 通过ClassUtil#getClassLoader获取classloader,调用虫重载方法,传入classloader和代理的接口. 加下来是具体创建代理的逻辑,1 首先校验接口的数量不能超过 65535,然后把所有接口名称拼接作为缓存的key. 这是Proxy的缓存的数据结构, 就是Map嵌套的WeakHashMap 数据结构. 这里对cache操作加了一把同步锁,首先是会根据classloader取获取HashMap的缓存,然后根据key 获取代理代理,如果缓存已存在, 则直接返回缓存,没有则判断value是否是PENDING_GENERATION_MARKER(即是Object阻塞标志),如果是 则一直调用wait进行等待待代理类的创建完成, 然后创建代理类计数器加1,然后实例化ClassGenerator类, 这是Dubbo首先的字节码操作,然后检查非public接口是否来自 不同的包, 然后遍历解析接口的方法,加入到CodeGenerator实例, 然欧创建默认生成ProxyInstance类名规则是 包名 + ".proxy" + 自增id, 生成Proxy的实例,是Proxy.class.getName() + id, 然后调用ClassGenerator生成的toClass底层是通过 javasist生成字节码,然后通过classloader记载到内存

Dubbo框架中没有提供将生成的字节码输出到文件的配置,所以我加了以下代码在生成字节码后,写入到文件:

  String proxyName = "$Proxy" + id +".class";
  Path path = Paths.get(proxy
  Files.write(path, mCtc.toBytecode(), new OpenOption[0]);

然后,下面是生成的字节码反编译的文件.

第一个是代理的实例的类.

public class Proxy0 extends Proxy implements DC {
   public Object newInstance(InvocationHandler var1) {
       return new proxy0(var1);
   }
   public Proxy0() {
   }
}

第二个是代理类

public class proxy0 implements DC, Destroyable, EchoService, DemoService {
   public static Method[] methods;
   private InvocationHandler handler;

   public Object invoke(String var1, String var2) throws Exception {
       Object[] var3 = new Object[]{var1, var2};
       Object var4 = this.handler.invoke(this, methods[0], var3);
       return (Object)var4;
   }

   public String get(CustomArgument var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[1], var2);
       return (String)var3;
   }

   public long timestamp() {
       Object[] var1 = new Object[0];
       Object var2 = this.handler.invoke(this, methods[2], var1);
       return var2 == null ? (long)0 : (Long)var2;
   }

   public int getSize(Object[] var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[3], var2);
       return var3 == null ? 0 : (Integer)var3;
   }

   public int getSize(String[] var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[4], var2);
       return var3 == null ? 0 : (Integer)var3;
   }

   public void $invoke(String var1, String var2) {
       Object[] var3 = new Object[]{var1, var2};
       this.handler.invoke(this, methods[5], var3);
   }

   public byte getbyte(byte var1) {
       Object[] var2 = new Object[]{new Byte(var1)};
       Object var3 = this.handler.invoke(this, methods[6], var2);
       return var3 == null ? (byte)0 : (Byte)var3;
   }

   public void sayHello(String var1) {
       Object[] var2 = new Object[]{var1};
       this.handler.invoke(this, methods[7], var2);
   }

   public String getThreadName() {
       Object[] var1 = new Object[0];
       Object var2 = this.handler.invoke(this, methods[8], var1);
       return (String)var2;
   }

   public int stringLength(String var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[9], var2);
       return var3 == null ? 0 : (Integer)var3;
   }

   public Type enumlength(Type[] var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[10], var2);
       return (Type)var3;
   }

   public Person getPerson(Person var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[11], var2);
       return (Person)var3;
   }

   public String testReturnType(String var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[12], var2);
       return (String)var3;
   }

   public List testReturnType1(String var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[13], var2);
       return (List)var3;
   }

   public CompletableFuture testReturnType2(String var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[14], var2);
       return (CompletableFuture)var3;
   }

   public CompletableFuture testReturnType3(String var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[15], var2);
       return (CompletableFuture)var3;
   }

   public CompletableFuture testReturnType4(String var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[16], var2);
       return (CompletableFuture)var3;
   }

   public CompletableFuture testReturnType5(String var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[17], var2);
       return (CompletableFuture)var3;
   }

   public String echo(String var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[18], var2);
       return (String)var3;
   }

   public Object $echo(Object var1) {
       Object[] var2 = new Object[]{var1};
       Object var3 = this.handler.invoke(this, methods[19], var2);
       return (Object)var3;
   }

   public void $destroy() {
       Object[] var1 = new Object[0];
       this.handler.invoke(this, methods[20], var1);
   }

   public proxy0() {
   }

   public proxy0(InvocationHandler var1) {
       this.handler = var1;
   }
}

总结: 今天主要分析了Dubbo中基于Javasist的动态代理的实现过程,针对Javasist具体详细操作需要读者对于java的字节码足够了解, 我之前分析过Java字节码文件的分析的文章,仅供参考.