6. Dubbo原理解析-代理之Javassist生成的伪代码

下面我们以伪代码来展示下生成的代理类

比如我们要对如下接口生成代理

public interface DemoService {

    String sayHello(String name);

    String  sayHelloAgain(Stringname);

}

生成的代理对象

public class  DemoService.proxy10001implements DemoService {

    public static Method[] methods =new Metod[]{“sayHello”, “sayHelloAgain”};

    private InvocationHandlerhandler;

    public voidDemoService.proxy10001() {}

    public voidDemoService.proxy10001(InvocationHandler handler) {

    this.handler= handler;

}

public String sayHello(String name){

    Objectret = handler.invoke(this, methods[0], new Object[]{name})

}

public String sayHello(String name){

    Objectret = handler.invoke(this, methods[1], new Object[]{name})

}

}

 

生成创建代理对象的代理

public class Proxy10001 extends Proxy {

    public void Proxy10001(){}

    public ObjectnewInstance(InvocationHandler h) {

    returnnew DemoService.proxy10001(h);

}

}

Proxy.getProxy(DemoService).newInstance(newInvokerInvocationHndler(invoker))代码最终创建了基于DemoService接口的代理对象

 

ClassGenerator是dubbo提供的基于javassist之上的封装,方便dubbo用于生成字节码操作,ClassGenerator主要用来收集java的类信息如接口,字段,方法,构造器等等信息,具体如何利用javassist生成字节码不在本文档介绍范围,如有兴趣请谷歌百度

 

Wrapper:抽象类定义了Class类中的常用的获取类信息的一些方法, Wrapper包装了一个接口或者一个类可以,可以通过Wrapper对实例对象进行赋值取值以及指定方法调用, 如果对spring原理有了解的话spring中对bean的操作都是通过BeanWrapper这个包装器进行了的, Dubbo的Wrapper的功能与它类似。

Wrapper生成包装类的过程其实同上面生成代理类过程类似,有兴趣的同学阅读下源代码即可, 下面我们通过伪代码来展示下生成的包装类的来了解它要达到的功能。

如我们要Wrapper的类

public class Impl1 implements I1{

    private String name = "youname";

    public String getName(){return name;}

    public void setName(String name){this. name = name;  }

    public void hello(String name)  {System.out.println( "hello " + name);}

    }

 

生成的包装类

public class Wrapper1234 extends Wrapper {

    public static String[] pns = newString[]{“name”};

       publicstatic Map pts = {“name” : “java.lang.String”};

       publicstatic String[] mns= new String[] {“getName”, “setName”, “hello” };

       publicstatic String[] dmns= new String[] {“getName”, “setName”, “hello” };

       publicString[] getPropertyNames(){ return pns; }

       publicboolean hasProperty(String n){ return pts.containsKey(n); }

       publicClass getPropertyType(String n){ return (Class)pts.get(n); }

       publicString[] getMethodNames(){ return mns; }

       publicString[] getDeclaredMethodNames(){ return dmns; }

 

       publicvoid setPropertyValue(Object o, String n, Object v) {

        Wrapper1234w;

        try { w= ((Wrapper1234) o);}

catch(Throwable e) {throw new IllegalArgumentException(e); }

        if (n.equals("name")){

           w.setName((java.lang.String) v);

           return;

        }

        throw 方法不存在异常

}

 

public ObjectgetPropertyValue(Object o, String n) {

        Wrapper1234w;

        try { w= ((Wrapper1234) o);

        } catch(Throwable e) { throw new IllegalArgumentException(e); }

        if (n.equals("name")){

           return w.getName();

        }

        抛方法不存在异常、

}

 

public ObjectinvokeMethod(Object o, String n, Class[] p, Object[] v)                                                                         throws java.lang.reflect.InvocationTargetException{

        Wrapper1234w;

        try { w= ((Wrapper1234) o);

        } catch(Throwable e) { throw new IllegalArgumentException(e); }

        try {

           if("getName".equals(n) && p.length == 0) {

               return w.getName();

            }

            if("setName".equals(n) && p.length == 1) {

               w.setName((java.lang.String) v[0]);

               return null;

            }

            if("hello".equals(n) && p.length == 1) {

               w.hello((java.lang.String) v[0]);

               return null;

            }

          }catch (Throwable e) {

           throw new java.lang.reflect.InvocationTargetException(e);

        }

        throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException( "Not found method " + n+ " in class Wrapper1234.");

    }

}

Wrapper1234是Wapper生成Impl1的包装对象, 对dubbo来说把各种无法预知的接口或者类转换成对dubbo可知的Wrapper对象子类, dubbo内部在向Invoker模型靠拢,Invoker是dubbo内部通用可执行对象, 这样一个远程调用只要根据请求invocation对象获取调用方法参数即可完成调用返回调用结果

代码交流 2021