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

时间: 2024-10-10 04:32:57

[编织消息框架][JAVA核心技术]动态代理应用8-IRpcReceive实现的相关文章

[编织消息框架][JAVA核心技术]动态代理介绍

由于java是种强类型静态语言,在执行时无法动态生成代码,静态语言基本都有这特性 动态生成代码有几种好处,也是弱类型语言的优点 1.部份逻辑可以实现热更新 2.远程调用实现非常适合 3.能动态生成扩展类,屏蔽复杂性,在原来基础上扩展功能,无破坏源码特性 静态语言也不是没有方案去解决,解决方案很多. 其中嵌入一个脚本引擎语言,就能弥补,还有动态代理技术 jdk 自带的动态代理是一种解决方案 cglib动态代理 spring默认使用 javassit 能在执行期修改class 顺便说下scala语言

[编织消息框架][JAVA核心技术]动态代理应用7-实现设计

根据设计生成两个接口,IRpcSend send方法返回数据要求包装成QResult对象 public interface IRpcSend { public <T> QResult<T> send(byte command, Object... args); } public interface IRpcReceive { public <T> T receive(byte command, Object... args); } public interface IR

[编织消息框架][JAVA核心技术]动态代理应用2

接下来如何实现 第一步:先把服务类,调用方法转换成数字,方便传输 第二步:提取元信息,提取又有三种方式,三种各有优点,最优方式是第一种 1.编译java时处理 2.程序启动时处理,预处理 3.调用时处理,懒处理 第三步:编码解释 第四步:请求方式 第五步:分布式支持 第一步: @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface QModel { short value(); } @Targ

[编织消息框架][JAVA核心技术]动态代理应用9-扫描class

之前介绍的annotationProcessor能在编译时生成自定义class,但有个缺点,只能每次添加/删除java文件才会执行,那天换了个人不清楚就坑大了 还记得之前介绍的编译时处理,懒处理,还有个预处理没介绍对吧 预处理:应用程序启动前做的处理,如setup 扫描class处理 1.从ClassLoader 和 System.getProperty("java.class.path") 读取所有classPath 2.解释每个classPath ,用正则匹配jar/class 文

[编织消息框架][JAVA核心技术]动态代理应用3

我们先使用懒处理实现提取接口类上的元信息: public abstract class QRpcFactory { public static <T> T loadProxy(Class<T> target, QNode... nodes) public static <T> T loadProxy(Class<T> target, long... ids) } 通过工厂类绑定session id 或 node 生成代理实例 RpcContext 是处理临时

[编织消息框架][JAVA核心技术]异常基础

Java异常体系结构 Thorwable类所有异常和错误的超类,有两个子类Error和Exception,分别表示错误和异常. 其中异常类Exception又分为运行时异常(RuntimeException)和编译时异常(checked Exception), 下面将详细讲述这些异常之间的区别与联系: 1.Error与Exception Error是程序无法处理的错误,比如OutOfMemoryError.ThreadDeath等.这些异常发生时, Java虚拟机(JVM)一般会选择线程终止.

代理模式 &amp; Java原生动态代理技术 &amp; CGLib动态代理技术

第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务.(其实就是在代理类中关联一个委托类的实例,然后在代理类中进行包装). UML图如下: 第二部分.在Java中实现代理模式  按照代理的创建时期,代理类可以分

java的动态代理

最近在研究这个java的ssh三大框架,当看到这个spring的aop(aspect-orinted-programming)的时候,其中提到了这个java的动态代理机制,这个动态代理,我以前似乎看过,但是那是设计模式的事情.所以有一次搜索到这个动态代理,对这个动态代理进行一个研究,记录自己的进步. spring的aop编程是一个面向切面的编程思想,和这个面向对象的编程是一个补充的关系,不是一个对立的关系.面向对象强调和使用的从上到下的层次关系,但是aop编程使用的是从左到右的关系.一个是纵的关

java中动态代理实现机制

JAVA各种动态代理实现的比较 接口 interface AddInterface{ int add(int a, int b); } interface SubInterface{ int sub(int a, int b); } 实现类 class Arithmetic implements AddInterface, SubInterface{ @Override public int sub(int a, int b) { return a-b; } @Override public i