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. 剑指offer编程题Java实现——面试题11数值的整数次方

    题目: 实现函数double power(double base,int exponent),求base的exponent次方.不得使用库函数,同时不需要考虑大数问题. 解题思路:最一般的方法实现数值 ...

  2. angular 1.26 版本 window.history.back() 自动去顶部

    在1.26版本,在url ("www.example.com#xx"),接着按back,会自动调到顶部,这是因为angular的默认设置 只要在config注入$AnchorScr ...

  3. 第34篇 再谈http协议

    从打开一个网址说起 当在浏览器中输入一个网址的时候,浏览器会渲染出对应的网页的内容.作为web开发人员来说,应该知道这个过程: 当输入的一个网址为域名的时候,浏览器则根据本机的网关和DNS服务器来解析 ...

  4. 第21篇 js四种继承方式

    js是一个很自由的语言,没有强类型的语言的那种限制,实现一个功能往往有很多做法.继承就是其中的一个,在js中继承大概可以分为四大类,上面一篇文章也提及过一些,下面开始详细说说js的继承. 1.原型继承 ...

  5. Linux CentOS下MySQL的安装配置之浅谈

    前期必备安装:VMware虚拟机,CentOS镜像[注意:Linux下使用CentOS   MySQL是不用在官网下载的,只需要配置就OK了] 下面开始正式操作: //CentOS安装MySQL之浅谈 ...

  6. sqlserver的一些小知识点

    1.高效分页sql和储存过程 select top 每页条数 * from ( select ROW_NUMBER() over (order by id)as nid ,* from table01 ...

  7. UIScrollView 和 UICollectionView 分页效果

    UIScrollView 和 UICollectionView 分页效果 UIScrollView可以滚动显示宽度或高度大于其bounds的内容.有些时候,需要有分页效果.每一页有统一的大小,相邻无缝 ...

  8. HTML 5入门知识——Drag

    HTML 5拖放 拖放的步骤: 1.对象元素的draggable属性设置为true,还需要注意的是a元素和img元素必须指定href. 2.编写与拖放有关的事件处理代码: DataTransfer对象 ...

  9. Maven工具的使用总结

    Maven作为构建工具,现在项目开发使用的越来越多,相对于ant和gradle,我更喜欢使用maven,先总结maven使用的一系列知识: 一.maven相关的网址: 名称 地址 其他 maven官网 ...

  10. iOS回顾笔记(06) -- AutoLayout从入门到精通

    iOS回顾笔记(06) -- AutoLayout从入门到精通 随着iOS设备屏幕尺寸的增多,当下无论是纯代码开发还是Xib/StoryBoard开发,自动布局已经是必备的开发技能了. 我使用自动布局 ...