基于javassist进行动态编程过程解析
今天在研究dubbo时,发现一个新的知识点,可以使用javassist包进行动态编程,hibernate也使用该包进行编程。晚上百度了很多资料,将它的特性以代码的形式展现出来。
packagecom.zhi.demo;
importjava.lang.reflect.Field;
importjavassist.ClassPool;
importjavassist.CtClass;
importjavassist.CtConstructor;
importjavassist.CtField;
importjavassist.CtMethod;
importjavassist.CtNewConstructor;
importjavassist.CtNewMethod;
importjavassist.Loader;
importjavassist.Modifier;
importjavassist.bytecode.AccessFlag;
/**
*Javassist动态编程测试
*
*@date2019年03月11日23:00:33
*
*/
publicclassJavassistTest{
publicstaticvoidmain(String[]args){
try{
test();
}catch(Exceptione){
e.printStackTrace();
}
}
privatestaticvoidtest()throwsException{
System.out.println("-------------------新增类------------------");
ClassPoolpool=ClassPool.getDefault();
//创建类
CtClassct=pool.makeClass("com.zhi.Person");
//让类实现Cloneable接口
ct.setInterfaces(newCtClass[]{pool.makeInterface("java.lang.Cloneable")});
//添加一个int类型的共有属性
CtFieldfieldId=newCtField(CtClass.intType,"id",ct);
fieldId.setModifiers(AccessFlag.PUBLIC);
ct.addField(fieldId);
//添加一个默认构造器
CtConstructorconstructor1=CtNewConstructor.make("publicPerson(){this.id=1;}",ct);
ct.addConstructor(constructor1);
//添加方法
CtMethodhelloM=CtNewMethod
.make("publicvoidhello(Stringdes){System.out.println(\"执行hello方法,\"+des+\",我的id是\"+this.id);}",ct);
ct.addMethod(helloM);
//将生成的.class文件保存到磁盘
ct.writeFile();
//加载目标类,可用ct.toClass()或newLoader(pool).loadClass()
Class>clazz=ct.toClass();
//Class>clazz=newLoader(pool).loadClass("com.zhi.Person");
//输出类基本信息
System.out.println("包名:"+clazz.getPackageName());
System.out.println("类名:"+clazz.getName());
System.out.println("简要类名:"+clazz.getSimpleName());
System.out.println("限定符:"+Modifier.toString(clazz.getModifiers()));
System.out.println("继承类:"+clazz.getSuperclass().getName());
Field[]fields=clazz.getDeclaredFields();
for(Fieldfield:fields){
System.out.println("属性名称:"+field.getName()+",属性类型:"+field.getType()+",限定符:"
+Modifier.toString(field.getModifiers()));
}
//构造一个对象,并执行hello方法
Objectob=clazz.getDeclaredConstructor().newInstance();
clazz.getMethod("hello",String.class).invoke(ob,"张三");
//解冻(执行toClass后会自动冻结)
ct.defrost();
System.out.println("-------------------修改类------------------");
//添加一个String类型的私有属性
CtFieldfieldName=newCtField(pool.get(String.class.getName()),"name",ct);
fieldName.setModifiers(AccessFlag.PRIVATE);
ct.addField(fieldName);
//添加带参的构造函数
CtConstructorconstructor2=newCtConstructor(newCtClass[]{pool.get(String.class.getName())},ct);
constructor2.setModifiers(Modifier.PUBLIC);
constructor2.setBody("{this.name=$1;}");
ct.addConstructor(constructor2);
ct.addMethod(CtNewMethod.make("publicvoidsetName(Stringname){this.name=name;}",ct));
ct.addMethod(CtNewMethod.make("publicStringgetName(){returnthis.name;}",ct));
ct.writeFile();
//加载类,若前面已用ct.toClass()进行加载,则这里不能再用ct.toClass()加载,否则会出错,同一个加载不能2次加载同一个类
clazz=newLoader(pool).loadClass("com.zhi.Person");
fields=clazz.getDeclaredFields();
for(Fieldfield:fields){
System.out.println("属性名称:"+field.getName()+",属性类型:"+field.getType()+",限定符:"
+Modifier.toString(field.getModifiers()));
}
ob=clazz.getDeclaredConstructor(String.class).newInstance("马云");
System.out.println("执行getName方法得到的值为:"+clazz.getMethod("getName").invoke(ob));
}
}
执行上面代码输出结果为:
-------------------新增类------------------ 包名:com.zhi 类名:com.zhi.Person 简要类名:Person 限定符:public 继承类:java.lang.Object 属性名称:id,属性类型:int,限定符:public 执行hello方法,张三,我的id是1 -------------------修改类------------------ 属性名称:id,属性类型:int,限定符:public 属性名称:name,属性类型:classjava.lang.String,限定符:private 执行getName方法得到的值为:马云
说明:
$0,$1,$2:分别代表this,第一个参数,第二个参数
$r:方法返回值的类型。
$_:方法返回值
依赖包
org.javassist javassist 3.24.1-GA
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。