[编织消息框架][JAVA核心技术]动态代理应用8-IRpcReceive实现
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实现的更多相关文章
- [编织消息框架][JAVA核心技术]动态代理介绍
由于java是种强类型静态语言,在执行时无法动态生成代码,静态语言基本都有这特性 动态生成代码有几种好处,也是弱类型语言的优点 1.部份逻辑可以实现热更新 2.远程调用实现非常适合 3.能动态生成扩展 ...
- [编织消息框架][JAVA核心技术]动态代理应用12-总结
动态代理这篇比较长,是框架组成的重要基础 回顾下学到的应用技术 1.异常应用 2.annotation技术 3.数值与逻辑分享 4.jdk.cglib.javassist等动态代理技术 5.懒处理.预 ...
- [编织消息框架][JAVA核心技术]动态代理应用4
基础部份: 接下来讲编译JAVA时,生成自定义class 我们用 javax.annotation.processing.AbstractProcessor 来处理 public abstract c ...
- [编织消息框架][JAVA核心技术]动态代理应用7-IRpcSend实现
根据设计生成两个接口,IRpcSend send方法返回数据要求包装成QResult对象 public interface IRpcSend { public <T> QResult< ...
- [编织消息框架][JAVA核心技术]动态代理应用4-annotationProcessor
基础部份: 接下来讲编译JAVA时,生成自定义class 我们用 javax.annotation.processing.AbstractProcessor 来处理 public abstract c ...
- [编织消息框架][JAVA核心技术]动态代理应用2
接下来如何实现 第一步:先把服务类,调用方法转换成数字,方便传输 第二步:提取元信息,提取又有三种方式,三种各有优点,最优方式是第一种 1.编译java时处理 2.程序启动时处理,预处理 3.调用时处 ...
- [编织消息框架][JAVA核心技术]动态代理应用5-javassist
基础部份: 修改class我们用到javassist,在pom.xml添加 <properties> <javassist.version>3.18.2-GA</java ...
- [编织消息框架][JAVA核心技术]动态代理应用9-扫描class
之前介绍的annotationProcessor能在编译时生成自定义class,但有个缺点,只能每次添加/删除java文件才会执行,那天换了个人不清楚就坑大了 还记得之前介绍的编译时处理,懒处理,还有 ...
- [编织消息框架][JAVA核心技术]动态代理应用10-水平扩展方案
服务分为系统服务同用户服务两种 水平扩展是基于系统服务,而拆分方式又有几种方案,按数据跟业务情况来做决策 1.每个服务独立存储(图1):每个服务只负责一个或多个领域实体存储,A服务不能直接修改B服务的 ...
随机推荐
- js本地预览图片
废话不说 直接上代码 <script type="text/javascript" src="http://code.jquery.com/jquery-late ...
- SpringMVC-HelloWorld (XML)
Spring2.5.6开启了Spring的注解时代,简化了的xml配置,提高了开发效率:但是,对于Spring的初学者,xml配置更容易理解的Spring的Ioc特性,aop特性:本文使用Maven构 ...
- C++ 11 学习2:空指针(nullptr) 和 基于范围的for循环(Range-based for loops)
3.空指针(nullptr) 早在 1972 年,C语言诞生的初期,常数0带有常数及空指针的双重身分. C 使用 preprocessor macroNULL 表示空指针, 让 NULL 及 0 分别 ...
- 学习HTML5一周的收获1
HTML5的基本结构 学习了title标签(显示网站名称),link标签(链接文件,可做网页美化) 快捷键:Ctrl+/ 注释 学习[meta标签] 1.charset属性:单独使用,设置文档字符集编 ...
- KoaHub.js -- 基于 Koa.js 平台的 Node.js web 快速开发框架之koahub-skip
koahub-skip koahub skip middleware koahub skip Conditionally skip a middleware when a condition is m ...
- Java反射机制深度剖析
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! Java反射机制是Java语言中一种很重要的机制,可能在工作中用到的机会不多,但是在很多框架中都有用到这种机制.我们知道Java是一门静态 ...
- Firefox52非HTTPS页面登录页面提示连接不安全的解决办法
背景: Firefox52版本开始,对于非HTTPS协议的登录页面,会提示链接不安全,如下图 解决办法很简单,上HTTPS协议(严重推荐,尤其是祖国这种特殊国情下,上HTTPS的协议好处多多,物超所值 ...
- 分享小知识:善用Group By排序
以下列举了公用表/临时表/聚合函数三个因素为例子(覆盖索引因素除外,有利用此类索引都会以索引顺序) 环境: Microsoft SQL Server 2014 (SP1-GDR) (KB319472 ...
- c#调用aapt查看apk文件信息功能实现
第一篇随笔就此开始. 1. 起源 思路源自于项目开发过程中.需要确认apk文件版本以验证其功能差异以便于定位问题,于是度娘,得到APK信息查看器(APK-info)这个工具,其版本号为0.2.它能显示 ...
- idea 使用常见问题处理
问题一: 项目中使用了 lombok,但是代码中一直报错,提示 bean 注入失败,set 和 get 方法都飘红 解决:idea 中安装 lombok 插件,安装方法自行百度吧~ 如果是用的 ecl ...