zoukankan      html  css  js  c++  java
  • Dubbo使用javassist生成动态类

    在服务(本地和远程)暴露的时候会调用proxyFactory.getInvoker方法

    具体位置:

    • 本地暴露:ServiceConfig#exportLocal line:538
    • 远程暴露: ServiceConfig#doExportUrlsFor1Protocol line:512

    会先调用AOP织入的类StubProxyFactoryWrapper#getInvoker

    然后执行JavassistProxyFactory#getInvoker

    JavassistProxyFactory#getInvoker如下

    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // getWrapper会生成代理类
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        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);
            }
        };
    }
    

    然后进入Wrapper#getWrapper--> Wrapper#makeWrapper, 具体代码就在这个makeWrapper方法里面

    例如现在暴露的服务如下:

    public interface TestService {
    
        String getData(String var1);
    
        List<String> getList();
    }
    

    那么生成的代理类如下:

    public class Wrapper0 extends com.alibaba.dubbo.common.bytecode.Wrapper {
    
        /**
         * 属性名, 属性类型
         */
        public static java.util.Map pts = new HashMap<String, Class<?>>();
        public static String[] pns = new String[0];
    
        /**
         * 所有的方法名
         */
        public static String[] mns = {"getData"};
        /**
         * 本类中的所有方法名
         */
        public static String[] dmns = {"getData"};
    
        /**
         * 一个方法中所有的参数类型  mts[n]属性的个数和方法的个数形同
         */
        public static Class[] mts0 = {String.class};
    
        public static Class[] mts1 = {List.class};
    
        @Override
        public String[] getPropertyNames() {
            return pns;
        }
    
        @Override
        public boolean hasProperty(String n) {
            return pts.containsKey(n);
        }
    
        @Override
        public Class getPropertyType(String n) {
            return (Class) pts.get(n);
        }
    
        @Override
        public String[] getMethodNames() {
            return mns;
        }
    
        @Override
        public String[] getDeclaredMethodNames() {
            return dmns;
        }
    
        @Override
        public void setPropertyValue(Object o, String n, Object v) {
            per.qiao.service.TestService w;
            try {
                w = ((per.qiao.service.TestService) o);
            } catch (Throwable e) {
                throw new IllegalArgumentException(e);
            }
            throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property "" + n + "" filed or setter method in class per.qiao.service.TestService.");
        }
    
        @Override
        public Object getPropertyValue(Object o, String n) {
            per.qiao.service.TestService w;
            try {
                w = ((per.qiao.service.TestService) o);
            } catch (Throwable e) {
                throw new IllegalArgumentException(e);
            }
            if (n.equals("list")) {
                return w.getList();
            }
            throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property "" + n + "" filed or setter method in class per.qiao.service.TestService.");
        }
    	
      	/**
      	 *  在调用接口时,就时调用的这个方法
      	    @param o 接口实例
      	    @param n 方法名
      	    @param p 参数类型
      	    @param v 参数
      	 */
        @Override
        public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
            per.qiao.service.TestService w;
            try {
                w = ((per.qiao.service.TestService) o);
            } catch (Throwable e) {
                throw new IllegalArgumentException(e);
            }
            try {
                //这个try范围内就是你所需要暴露的所有方法
                if ("getData".equals(n) && p.length == 1) {
                    return w.getData((java.lang.String) v[0]);
                }
                if ("getList".equals(n) && p.length == 0) {
                    return w.getList();
                }
            } catch (Throwable e) {
                throw new java.lang.reflect.InvocationTargetException(e);
            }
            throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method "" + n + "" in class per.qiao.service.TestService.");
        }
    }
    

    javassist生成动态代理类的示例

    public class CompilerByJavassist {
    
        public static void main(String[] args) throws Exception {
            // ClassPool:CtClass对象的容器
            ClassPool pool = ClassPool.getDefault();
    
            // 通过ClassPool生成一个public新类Emp.java
            CtClass ctClass = pool.makeClass("per.qiao.javassist.Qiao");
    
            // 添加属性 private String name
            CtField nameFild = new CtField(pool.getCtClass("java.lang.String"), "name", ctClass);
            nameFild.setModifiers(Modifier.PRIVATE);
            ctClass.addField(nameFild);
    
            // 其次添加熟悉privtae int age
            CtField ageField = new CtField(pool.getCtClass("int"), "age", ctClass);
            ageField.setModifiers(Modifier.PRIVATE);
            ctClass.addField(ageField);
    
            // 为属性name和age添加getXXX和setXXX方法
            ctClass.addMethod(CtNewMethod.getter("getName", nameFild));
            ctClass.addMethod(CtNewMethod.setter("setName", nameFild));
            ctClass.addMethod(CtNewMethod.getter("getAge", ageField));
            ctClass.addMethod(CtNewMethod.setter("setAge", ageField));
    
            // 添加构造函数
            CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, ctClass);
            // 为构造函数设置函数体
            StringBuffer buffer = new StringBuffer();
            buffer.append("{
    ").append("name="qiaogege";
    ").append("age=25;
    }");
            ctConstructor.setBody(buffer.toString());
            // 把构造函数添加到新的类中
            ctClass.addConstructor(ctConstructor);
    
    
            // 添加自定义方法  public void printInfo {...}
            CtMethod ctMethod = new CtMethod(CtClass.voidType, "printInfo", new CtClass[] {}, ctClass);
            // 为自定义方法设置修饰符
            ctMethod.setModifiers(Modifier.PUBLIC);
            // 为自定义方法设置函数体
            StringBuffer buffer2 = new StringBuffer();
            buffer2.append("{
    System.out.println("begin!");
    ")
                    .append("System.out.println(name);
    ")
                    .append("System.out.println(age);
    ")
                    .append("System.out.println("over!");
    ").append("}");
            ctMethod.setBody(buffer2.toString());
            ctClass.addMethod(ctMethod);
    
    
            //最好生成一个class
            Class<?> clazz = ctClass.toClass();
            Object obj = clazz.newInstance();
            //ctClass.debugWriteFile("E://Qiao.class");
    
            //反射 执行方法
            obj.getClass().getMethod("printInfo", new Class[] {})
                    .invoke(obj, new Object[] {});
    
            ctClass.debugWriteFile("E://Emp.class");
            // 把生成的class文件写入文件
            byte[] byteArr = ctClass.toBytecode();
            FileOutputStream fos = new FileOutputStream(new File("E://Qiao.class"));
            fos.write(byteArr);
            fos.close();
        }
    
    }
    

    生成的Class文件放入IDEA中反编译后的结果如下

    public class Qiao {
        private String name = "qiaogege";
        private int age = 25;
    
        public String getName() {
            return this.name;
        }
    
        public void setName(String var1) {
            this.name = var1;
        }
    
        public int getAge() {
            return this.age;
        }
    
        public void setAge(int var1) {
            this.age = var1;
        }
    
        public Qiao() {
        }
    
        public void printInfo() {
            System.out.println("begin!");
            System.out.println(this.name);
            System.out.println(this.age);
            System.out.println("over!");
        }
    }
    

    小结:

    1. Dubbo通过javassist动态生成一个代理类对象,该对象不同于普通的javassist生成的对象,而是只记录了暴露接口中的方法的相关参数,生成一个Wrapper类型的对象,并保存在WRAPPER_MAP中,通过invokeMethod方法来执行相应的方法
    2. 再将生成的Wrapper对象包装在AbstractProxyInvoker中进行服务暴露
    

    还有一篇 dubbo中使用动态代理

  • 相关阅读:
    2017-2018-1 20155226 20155234 实验一 开发环境的熟悉
    2017-2018-1 20155234 《信息安全系统设计基础》第四周课堂实践
    2017-2018-1 20155234第三周《信息安全系统设计基础》学习总结
    2017-2018-1 20155234第一周《信息安全系统设计基础》学习总结
    20155234 实验五 网络编程与安全
    20155234 2016-2017-2《Java程序设计》课程总结
    20155234 《Java程序设计》实验四 (Android程序设计)实验报告
    20155234 实验三 敏捷开发与XP实践
    2017-2018-1 20155231 《信息安全系统设计基础》第9周学习总结
    2017-2018-1 20155231 实验三 实时系统
  • 原文地址:https://www.cnblogs.com/qiaozhuangshi/p/11007024.html
Copyright © 2011-2022 走看看