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

时间:2024-04-07 22:02:55
     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 处理