private static Map<Short, Map<Byte, Method>> RECEIVE_METHOD_INFO = new HashMap<>();

     public static <T> T registerReceiveProxy(Object obj) {
Class<?> target = obj.getClass();
if (target.isInterface()) {
throw new RuntimeException("class is Interface : " + target);
}
QModel modelAnno = ReflectUtil.getAnno(target, QModel.class);
String proxyClassName = target.getCanonicalName() + "$$receive$$";
ClassPool classPool = JavassistHepler.classPool;
CtClass ctClass = classPool.makeClass(proxyClassName); try {
// 设置接口,继承 target
CtClass[] interfaces = new CtClass[1];
interfaces[0] = classPool.get(IRpcReceive.class.getName());
ctClass.setInterfaces(interfaces);
ctClass.setSuperclass(JavassistHepler.getCtClass(target));
{
// 添加this字段
final String ctxName = target.getName();
CtField ctField = new CtField(classPool.get(ctxName), "_this", ctClass);
ctField.setModifiers(Modifier.PRIVATE | Modifier.FINAL);
// 添加json 忽略anno
ctField.getFieldInfo2().addAttribute(JavassistHepler.addAnno(JsonIgnore.class, ctClass));
ctClass.addField(ctField);
} Map<Byte, Method> methods = new HashMap<>();
RECEIVE_METHOD_INFO.put(modelAnno.value(), methods); // 生成代理方法
ReflectUtil.foreachMethods(target, (method) -> {
QCommond commond = method.getAnnotation(QCommond.class);
if (commond == null) {
return;
}
methods.put(commond.value(), method);
String resultType = "";
if (void.class != method.getReturnType()) {
resultType = " return ($r) ";
}
final String body = "{ " + resultType + "_this." + method.getName() + "($$); }";
JavassistHepler.addMethod(ctClass, method, body);
}); // 生成receive method
{
final String body = "{return ($r) " + QRpcFactory.class.getName() + ".proxyReceive(_this,$2, (short)" + modelAnno.value() + " ,(byte) $1);}";
JavassistHepler.addMethod(ctClass, RECEIVE_METHOD, body);
} // 添加构造方法 new XXProxy(XX)
CtConstructor ctConstructor = new CtConstructor(JavassistHepler.toCtClassArray(target), ctClass);
ctConstructor.setBody("{ this._this = $1; }");
ctConstructor.setModifiers(Modifier.PUBLIC);
ctClass.addConstructor(ctConstructor);
Class<?> newClass = ctClass.toClass();
Constructor<T> constructor = (Constructor<T>) newClass.getConstructor(target);
constructor.setAccessible(true);
ctClass.detach();
Object ret = constructor.newInstance(obj);
RECEIVE.put(modelAnno.value(), (IRpcReceive) ret);
return (T) ret;
} catch (Exception e) {
throw new RuntimeException(e);
}
} // 因为 javassist $$ 表达式访问的 参数类型 为 object 获取不到目标类型,所以只能用 invoke 处理
public static Object proxyReceive(Object target, Object[] args, short model, byte commondIndex) {
Map<Byte, Method> methods = RECEIVE_METHOD_INFO.get(model);
try {
return methods.get(commondIndex).invoke(target, args);
} catch (Exception e) {
throw new QRpcException(QCode.ENHANCE_ERROR_RPC_NOFIND_MODEL, "proxyReceive ", e);
}
}
}
    @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 处理

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

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

    由于java是种强类型静态语言,在执行时无法动态生成代码,静态语言基本都有这特性 动态生成代码有几种好处,也是弱类型语言的优点 1.部份逻辑可以实现热更新 2.远程调用实现非常适合 3.能动态生成扩展 ...

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

    动态代理这篇比较长,是框架组成的重要基础 回顾下学到的应用技术 1.异常应用 2.annotation技术 3.数值与逻辑分享 4.jdk.cglib.javassist等动态代理技术 5.懒处理.预 ...

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

    基础部份: 接下来讲编译JAVA时,生成自定义class 我们用 javax.annotation.processing.AbstractProcessor 来处理 public abstract c ...

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

    根据设计生成两个接口,IRpcSend send方法返回数据要求包装成QResult对象 public interface IRpcSend { public <T> QResult< ...

  5. [编织消息框架][JAVA核心技术]动态代理应用4-annotationProcessor

    基础部份: 接下来讲编译JAVA时,生成自定义class 我们用 javax.annotation.processing.AbstractProcessor 来处理 public abstract c ...

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

    接下来如何实现 第一步:先把服务类,调用方法转换成数字,方便传输 第二步:提取元信息,提取又有三种方式,三种各有优点,最优方式是第一种 1.编译java时处理 2.程序启动时处理,预处理 3.调用时处 ...

  7. [编织消息框架][JAVA核心技术]动态代理应用5-javassist

    基础部份: 修改class我们用到javassist,在pom.xml添加 <properties> <javassist.version>3.18.2-GA</java ...

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

    之前介绍的annotationProcessor能在编译时生成自定义class,但有个缺点,只能每次添加/删除java文件才会执行,那天换了个人不清楚就坑大了 还记得之前介绍的编译时处理,懒处理,还有 ...

  9. [编织消息框架][JAVA核心技术]动态代理应用10-水平扩展方案

    服务分为系统服务同用户服务两种 水平扩展是基于系统服务,而拆分方式又有几种方案,按数据跟业务情况来做决策 1.每个服务独立存储(图1):每个服务只负责一个或多个领域实体存储,A服务不能直接修改B服务的 ...

随机推荐

  1. mysql之连接localhost与127.0.0.1的区别

    引言 在聊天群里看到有人提到 mysql 中 localhost 和 127.0.0.1 的区别,这个之前并没有仔细考虑过.现在来学习下. localhost 与 127.0.0.1 区别 local ...

  2. MyBatis 源码分析——类型处理器

    官网上面讲到:无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型.那 ...

  3. Java系统属性与Preferences API的简单介绍

    系统属性在和Preferences API都是键值对,前者只能当前应用程序中共享数据,而后者可以在用户的各个应用或用户之间共享数据. 系统属性 Java 的系统属性决定了 Java 程序实际运行的环境 ...

  4. Fraction to Recurring Decimal leetcode

    Given two integers representing the numerator and denominator of a fraction, return the fraction in ...

  5. 求int型正整数在内存中存储时1的个数

    题目描述: 输入一个int型的正整数,计算出该int型数据在内存中存储时1的个数. 输入描述: 输入一个整数(int类型) 输出描述: 这个数转换成2进制后,输出1的个数 输入例子: 5 输出例子: ...

  6. 1741: [Usaco2005 nov]Asteroids 穿越小行星群

    1741: [Usaco2005 nov]Asteroids 穿越小行星群 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 231  Solved: 166 ...

  7. 3359: [Usaco2004 Jan]矩形

    3359: [Usaco2004 Jan]矩形 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 8  Solved: 5[Submit][Status] ...

  8. ABP入门系列(14)——应用BootstrapTable表格插件

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1. 引言 之前的文章ABP入门系列(7)--分页实现讲解了如何进行分页展示,但其分页展示仅适用于 ...

  9. javascript-基本数据类型和转换

    ECMAScript中有5种基本数据类型:Undefined.Null.Boolean.Number.String.还有1种复杂数据类型-Object,Object实质上是由一组无序的名值对(键值对) ...

  10. HTTP协议&SOCKET协议

    一. HTTP协议是什么? 我们在浏览器的地址栏里输入的网站地址叫做 URL(UniformResourceLocator,统一资源定位符).就像每家每户都有一个门牌地址一样,每个网页也都有一个Int ...