[编织消息框架][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 处理
作者: | solq |
博客地址: | http://www.cnblogs.com/solq111 |
博客版权: | 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。 如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。 淘宝店: 海豚极货店 QQ群:9547527 |
如果你热爱生活、热爱编程、热爱吉他。扫一扫加我微信 |
我的新书《编织消息框架》目前进行中,感谢大家关注! |
本作品采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。 |