zoukankan      html  css  js  c++  java
  • [编织消息框架][JAVA核心技术]动态代理应用8-IRpcReceive实现

     1     private static Map<Short, Map<Byte, Method>> RECEIVE_METHOD_INFO = new HashMap<>();
     2 
     3     public static <T> T registerReceiveProxy(Object obj) {
     4         Class<?> target = obj.getClass();
     5         if (target.isInterface()) {
     6             throw new RuntimeException("class is Interface : " + target);
     7         }
     8         QModel modelAnno = ReflectUtil.getAnno(target, QModel.class);
     9         String proxyClassName = target.getCanonicalName() + "$$receive$$";
    10         ClassPool classPool = JavassistHepler.classPool;
    11         CtClass ctClass = classPool.makeClass(proxyClassName);
    12 
    13         try {
    14             // 设置接口,继承 target
    15             CtClass[] interfaces = new CtClass[1];
    16             interfaces[0] = classPool.get(IRpcReceive.class.getName());
    17             ctClass.setInterfaces(interfaces);
    18             ctClass.setSuperclass(JavassistHepler.getCtClass(target));
    19             {
    20                 // 添加this字段
    21                 final String ctxName = target.getName();
    22                 CtField ctField = new CtField(classPool.get(ctxName), "_this", ctClass);
    23                 ctField.setModifiers(Modifier.PRIVATE | Modifier.FINAL);
    24                 // 添加json 忽略anno
    25                 ctField.getFieldInfo2().addAttribute(JavassistHepler.addAnno(JsonIgnore.class, ctClass));
    26                 ctClass.addField(ctField);
    27             }
    28 
    29             Map<Byte, Method> methods = new HashMap<>();
    30             RECEIVE_METHOD_INFO.put(modelAnno.value(), methods);
    31 
    32             // 生成代理方法
    33             ReflectUtil.foreachMethods(target, (method) -> {
    34                 QCommond commond = method.getAnnotation(QCommond.class);
    35                 if (commond == null) {
    36                     return;
    37                 }
    38                 methods.put(commond.value(), method);
    39                 String resultType = "";
    40                 if (void.class != method.getReturnType()) {
    41                     resultType = " return ($r) ";
    42                 }
    43                 final String body = "{ " + resultType + "_this." + method.getName() + "($$); }";
    44                 JavassistHepler.addMethod(ctClass, method, body);
    45             });
    46 
    47             // 生成receive method
    48             {
    49                 final String body = "{return ($r) " + QRpcFactory.class.getName() + ".proxyReceive(_this,$2, (short)" + modelAnno.value() + "  ,(byte) $1);}";
    50                 JavassistHepler.addMethod(ctClass, RECEIVE_METHOD, body);
    51             }
    52 
    53             // 添加构造方法 new XXProxy(XX)
    54             CtConstructor ctConstructor = new CtConstructor(JavassistHepler.toCtClassArray(target), ctClass);
    55             ctConstructor.setBody("{ this._this = $1; }");
    56             ctConstructor.setModifiers(Modifier.PUBLIC);
    57             ctClass.addConstructor(ctConstructor);
    58             Class<?> newClass = ctClass.toClass();
    59             Constructor<T> constructor = (Constructor<T>) newClass.getConstructor(target);
    60             constructor.setAccessible(true);
    61             ctClass.detach();
    62             Object ret = constructor.newInstance(obj);
    63             RECEIVE.put(modelAnno.value(), (IRpcReceive) ret);
    64             return (T) ret;
    65         } catch (Exception e) {
    66             throw new RuntimeException(e);
    67         }
    68     }
    69 
    70     // 因为 javassist $$ 表达式访问的 参数类型 为 object 获取不到目标类型,所以只能用 invoke 处理
    71     public static Object proxyReceive(Object target, Object[] args, short model, byte commondIndex) {
    72         Map<Byte, Method> methods = RECEIVE_METHOD_INFO.get(model);
    73         try {
    74             return methods.get(commondIndex).invoke(target, args);
    75         } catch (Exception e) {
    76             throw new QRpcException(QCode.ENHANCE_ERROR_RPC_NOFIND_MODEL, "proxyReceive ", e);
    77         }
    78     }
    79 }
        @Test
        public void testReceive() {    
            TestObject proxy = QRpcFactory.registerReceiveProxy(new TestObjectImpl());
    
            proxy.a(1, "b");
            proxy.setAge(30);
            QResult<Integer> ret = proxy.getAge();
            System.out.println(ret.getResult());
    
            Object[] args = new Object[1];
            args[0] =18;
                
            ((IRpcReceive) proxy).receive((byte) 2, args);
    
            ret = proxy.getAge();
            System.out.println(ret.getResult());
            args[0] = new TestObject1();
            ((IRpcReceive) proxy).receive((byte) 4, args);
        }
        
        @Test
        public void testObjectArgs() {
            QRpcFactory.registerReceiveProxy(new TestObjectImpl());
            IRpcReceive obj = QRpcFactory.loadReceiveProxy((short)1);
            int a=30;
            Integer b= 30;
            double c=1d;
            List<Integer> d = new ArrayList<>();
            Integer[] e = new Integer[0];
            Object[] args = new Object[5];
            args[0] =a;
            args[1] =b;
            args[2] =c;
            args[3] =d;
            args[4] =e;
    
            obj.receive((byte)5, args);
        }

    在实际开发时 因为 javassist $$ 表达式访问的参数类型为object 获取不到目标类型,编译时出现错误

    Type 'java/lang/Object' (current frame, stack[1]) is not assignable to integer

    所以只能用 invoke 处理 

  • 相关阅读:
    thinkPHP入门之二
    thinkPHP入门
    斐波那契数列,冒泡排序,选择排序,数组去重
    jquery-懒加载插件
    本地存储之cookie
    javascript的快速排序法
    [luogu2165 AHOI2009] 飞行棋 (枚举)
    [luogu2576 SCOI2010] 幸运数字 (容斥原理)
    [luogu2587 ZJOI2008] 泡泡堂 (贪心)
    [luogu2602 ZJOI2010] 数字计数 (数位dp)
  • 原文地址:https://www.cnblogs.com/solq111/p/6694484.html
Copyright © 2011-2022 走看看