Dubbo使用javassist生成动态类
在服务(本地和远程)暴露的时候会调用proxyFactory.getInvoker方法
具体位置:
- 本地暴露:ServiceConfig#exportLocal line:538
- 远程暴露: ServiceConfig#doExportUrlsFor1Protocol line:512
会先调用AOP织入的类StubProxyFactoryWrapper#getInvoker
然后执行JavassistProxyFactory#getInvoker
JavassistProxyFactory#getInvoker如下
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// getWrapper会生成代理类
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
然后进入Wrapper#getWrapper--> Wrapper#makeWrapper, 具体代码就在这个makeWrapper方法里面
例如现在暴露的服务如下:
public interface TestService {
String getData(String var1);
List<String> getList();
}
那么生成的代理类如下:
public class Wrapper0 extends com.alibaba.dubbo.common.bytecode.Wrapper {
/**
* 属性名, 属性类型
*/
public static java.util.Map pts = new HashMap<String, Class<?>>();
public static String[] pns = new String[0];
/**
* 所有的方法名
*/
public static String[] mns = {"getData"};
/**
* 本类中的所有方法名
*/
public static String[] dmns = {"getData"};
/**
* 一个方法中所有的参数类型 mts[n]属性的个数和方法的个数形同
*/
public static Class[] mts0 = {String.class};
public static Class[] mts1 = {List.class};
@Override
public String[] getPropertyNames() {
return pns;
}
@Override
public boolean hasProperty(String n) {
return pts.containsKey(n);
}
@Override
public Class getPropertyType(String n) {
return (Class) pts.get(n);
}
@Override
public String[] getMethodNames() {
return mns;
}
@Override
public String[] getDeclaredMethodNames() {
return dmns;
}
@Override
public void setPropertyValue(Object o, String n, Object v) {
per.qiao.service.TestService w;
try {
w = ((per.qiao.service.TestService) o);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class per.qiao.service.TestService.");
}
@Override
public Object getPropertyValue(Object o, String n) {
per.qiao.service.TestService w;
try {
w = ((per.qiao.service.TestService) o);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
if (n.equals("list")) {
return w.getList();
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class per.qiao.service.TestService.");
}
/**
* 在调用接口时,就时调用的这个方法
@param o 接口实例
@param n 方法名
@param p 参数类型
@param v 参数
*/
@Override
public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
per.qiao.service.TestService w;
try {
w = ((per.qiao.service.TestService) o);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
try {
//这个try范围内就是你所需要暴露的所有方法
if ("getData".equals(n) && p.length == 1) {
return w.getData((java.lang.String) v[0]);
}
if ("getList".equals(n) && p.length == 0) {
return w.getList();
}
} catch (Throwable e) {
throw new java.lang.reflect.InvocationTargetException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + n + "\" in class per.qiao.service.TestService.");
}
}
javassist生成动态代理类的示例
public class CompilerByJavassist {
public static void main(String[] args) throws Exception {
// ClassPool:CtClass对象的容器
ClassPool pool = ClassPool.getDefault();
// 通过ClassPool生成一个public新类Emp.java
CtClass ctClass = pool.makeClass("per.qiao.javassist.Qiao");
// 添加属性 private String name
CtField nameFild = new CtField(pool.getCtClass("java.lang.String"), "name", ctClass);
nameFild.setModifiers(Modifier.PRIVATE);
ctClass.addField(nameFild);
// 其次添加熟悉privtae int age
CtField ageField = new CtField(pool.getCtClass("int"), "age", ctClass);
ageField.setModifiers(Modifier.PRIVATE);
ctClass.addField(ageField);
// 为属性name和age添加getXXX和setXXX方法
ctClass.addMethod(CtNewMethod.getter("getName", nameFild));
ctClass.addMethod(CtNewMethod.setter("setName", nameFild));
ctClass.addMethod(CtNewMethod.getter("getAge", ageField));
ctClass.addMethod(CtNewMethod.setter("setAge", ageField));
// 添加构造函数
CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, ctClass);
// 为构造函数设置函数体
StringBuffer buffer = new StringBuffer();
buffer.append("{\n").append("name=\"qiaogege\";\n").append("age=25;\n}");
ctConstructor.setBody(buffer.toString());
// 把构造函数添加到新的类中
ctClass.addConstructor(ctConstructor);
// 添加自定义方法 public void printInfo {...}
CtMethod ctMethod = new CtMethod(CtClass.voidType, "printInfo", new CtClass[] {}, ctClass);
// 为自定义方法设置修饰符
ctMethod.setModifiers(Modifier.PUBLIC);
// 为自定义方法设置函数体
StringBuffer buffer2 = new StringBuffer();
buffer2.append("{\nSystem.out.println(\"begin!\");\n")
.append("System.out.println(name);\n")
.append("System.out.println(age);\n")
.append("System.out.println(\"over!\");\n").append("}");
ctMethod.setBody(buffer2.toString());
ctClass.addMethod(ctMethod);
//最好生成一个class
Class<?> clazz = ctClass.toClass();
Object obj = clazz.newInstance();
//ctClass.debugWriteFile("E://Qiao.class");
//反射 执行方法
obj.getClass().getMethod("printInfo", new Class[] {})
.invoke(obj, new Object[] {});
ctClass.debugWriteFile("E://Emp.class");
// 把生成的class文件写入文件
byte[] byteArr = ctClass.toBytecode();
FileOutputStream fos = new FileOutputStream(new File("E://Qiao.class"));
fos.write(byteArr);
fos.close();
}
}
生成的Class文件放入IDEA中反编译后的结果如下
public class Qiao {
private String name = "qiaogege";
private int age = 25;
public String getName() {
return this.name;
}
public void setName(String var1) {
this.name = var1;
}
public int getAge() {
return this.age;
}
public void setAge(int var1) {
this.age = var1;
}
public Qiao() {
}
public void printInfo() {
System.out.println("begin!");
System.out.println(this.name);
System.out.println(this.age);
System.out.println("over!");
}
}
小结:
1. Dubbo通过javassist动态生成一个代理类对象,该对象不同于普通的javassist生成的对象,而是只记录了暴露接口中的方法的相关参数,生成一个Wrapper类型的对象,并保存在WRAPPER_MAP中,通过invokeMethod方法来执行相应的方法
2. 再将生成的Wrapper对象包装在AbstractProxyInvoker中进行服务暴露
还有一篇 dubbo中使用动态代理
Dubbo使用javassist生成动态类的更多相关文章
- c# 动态生成继承类并实现序列化特性
项目来源 App传过来的字段是动态的,希望能保证扩展性,返回时,把所需要的字段与数据融合后再返回过去 数据是第3方来源的,但是序列化后的结果又希望能并列返回 如:App传过来 一个设备Id,客户Id等 ...
- JAVA基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架
1.类加载器 ·简要介绍什么是类加载器,和类加载器的作用 ·Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader ...
- 将dubbo中使用的动态代理作为工具类
ReflectUtils package per.qiao.util.javassistUtil; import java.lang.reflect.Constructor; import java. ...
- JSP-讲解(生成java类、静态导入与动态导入)
一.JSP技术简介 JSP是Java Server Page的缩写,它是Servlet的扩展,它的作用是简化网站的创建和维护. JSP是HTML代码与Java代码的混合体. JSP文件通常以JSP或J ...
- Java中动态代理技术生成的类与原始类的区别 (转)
用动态代理的时候,对它新生成的类长什么样子感到好奇.有幸通过一些资料消除了心里的疑惑. 平时工作使用的Spring框架里面有一个AOP(面向切面)的机制,只知道它是把类重新生成了一遍,在切面上加上了后 ...
- Java中动态代理技术生成的类与原始类的区别
用动态代理的时候,对它新生成的类长什么样子感到好奇.有幸通过一些资料消除了心里的疑惑. 平时工作使用的Spring框架里面有一个AOP(面向切面)的机制,只知道它是把类重新生成了一遍,在切面上加上了后 ...
- JDK动态代理[4]----ProxyGenerator生成代理类的字节码文件解析
通过前面几篇的分析,我们知道代理类是通过Proxy类的ProxyClassFactory工厂生成的,这个工厂类会去调用ProxyGenerator类的generateProxyClass()方法来生成 ...
- Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架
类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...
- java web(七): mybatis的动态sql和mybatis generator自动生成pojo类和映射文件
前言: MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据 不同条件拼接 SQL 语句的痛苦.例如拼接时要确保不能忘记添加必要的空格,还 ...
随机推荐
- cogs 998. [東方S2] 帕秋莉·诺蕾姬
二次联通门 : cogs 998. [東方S2] 帕秋莉·诺蕾姬 交上去后发现自己没上榜 就想着加点黑科技 把循环展开一下 结果WA了.. 万恶的姆Q /* cogs 998. [東方S2] 帕秋莉· ...
- 第09组 Alpha事后诸葛亮
组长博客链接 组长博客 参考邹欣老师的问题模板进行总结思考 设想和目标(2分) 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 解决的问题 我们软件初期旨在解决 ...
- .net web.config中配置字符串中特殊字符的处理
https://www.cnblogs.com/zzmzaizai/archive/2008/01/30/1059191.html 如果本身字符串中有特殊字符,如分号,此时就需要用单引号整体包裹起来, ...
- pyqt(day1)
参考代码地址:https://github.com/cxinping/Pyqt5 pyqt在线帮助文档:https://www.riverbankcomputing.com/static/Docs/P ...
- 冰多多团队-第五次Scrum会议
冰多多团队-第五次Scrum会议 工作情况 团队成员 已完成任务 待完成任务 zpj 部分Action整合, 接入语音接口,整合项目解决兼容性问题 ASR bug修复 牛雅哲 跑通了科大讯飞语法识别的 ...
- 【用例篇】Xmind转为csv 导入禅道
用过禅道的都知道,用例维护实在是太不方便了,有人推荐了一种方法,用Xmind先编写用例(思路比较清晰),写好之后借助工具(xmind2testcase)将用例转为CSV格式,之后再导入禅道 参考资料: ...
- tp使用ajaxReturn返回二维数组格式的字符串,前台如何获取非乱码
参考: https://www.cnblogs.com/jiqing9006/p/5000849.html https://blog.csdn.net/zengxiangxuan123456/arti ...
- Java学习-054-Mybatis IN查询,通过 foreach 获取列表数据
通过如下语句查询商品订单信息: ,,,) 在 Mapper.java 中定义如下接口: List<GoodsOrder> findGoodsOrderByIds(String ids); ...
- Eclipse 修改(重定向)SVN地址
由于SVN服务器IP变了,需要重定向SVN的路径 1.点击右上角1位置的按钮,然后选择需要打开的窗口(SVN资源库) 2.右击SVN资源库中的项目,选择重定向,然后修改新的URL即可 1. 进入本地s ...
- json 格式化处理工具
json 格式化处理工具 用于JSON的快速命令行处理工具,简单无依赖. 我这边列举一些最常用的: 调试 http 请求时打印格式化后的数据 格式化本地或或流中的数据 获取 json 的键值或进行执行 ...