[编织消息框架][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 处理 

posted @ 2017-04-12 11:03  solq321  阅读(246)  评论(0编辑  收藏  举报