Java知识点总结(动态字节码操作-Javassist的API使用)
@(Java知识点总结)[Java, 动态字节码操作]
参考文章: 传送
操作示例:
public @interface Author {
String name();
int year();
}
@Author(name = "gs",year=2015)
public class Emp {
private int num;
private String name;
public Emp() {
}
public Emp(int num, String name) {
this();
this.num = num;
this.name = name;
}
public void sayHello(String name){
System.out.print("你好,");
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;
/**
* 测试 javassist 的 API
*
* @author Administrator
*
*/
public class Test11 {
// 通过类名加载已有的类
public static void test1(ClassPool pool, CtClass cc) {
try {
cc = pool.get("com.gs.Emp");
byte[] bytes = cc.toBytecode(); // 转化为字节码
System.out.println(Arrays.toString(bytes));
System.out.println(cc.getName()); // 获取类名
System.out.println(cc.getSimpleName());
System.out.println(cc.getSuperclass()); // 获取父类
System.out.println(cc.getInterfaces()); // 获取接口
} catch (Exception e) {
e.printStackTrace();
}
}
// 动态生成一个方法,并调用
public static void test2(ClassPool pool, CtClass cc) {
try {
/*当CtClass对象通过writeFile()、toClass()、toBytecode()转化为Class后,
* Javassist冻结了CtClass对象,因此,JVM不允许再次加载Class文件,所以不允许对其修改。
因此,若想对CtClass对象进行修改,必须对其进行解冻,通过defrost()方法进行*/
cc.defrost();
// 生成一个方法
CtMethod add = CtNewMethod.make("public int add(int a,int b){return $1+$2;}", cc);
// 生成一个方法
CtMethod subtraction = new CtMethod(CtClass.intType, "subtraction",
new CtClass[] { CtClass.intType, CtClass.intType }, cc);
subtraction.setModifiers(Modifier.PUBLIC);
subtraction.setBody("return $1-$2;");
cc.addMethod(add);
cc.addMethod(subtraction);
// 通过反射调用生成的方法
Class clazz = cc.toClass();
Emp emp = (Emp) clazz.newInstance();
// Method method = clazz.getDeclaredMethod("add", new
// Class[]{int.class,int.class});
Method method = clazz.getDeclaredMethod("subtraction", new Class[] { int.class, int.class });
Object result = method.invoke(emp, 200, 300);
System.out.println(result);
} catch (Exception e) {
}
}
// 方法体前面和后面加执行语句
public static void test3(ClassPool pool, CtClass cc) {
try {
cc.defrost();
CtMethod m1 = cc.getDeclaredMethod("sayHello", new CtClass[] { pool.get("java.lang.String") });
m1.insertBefore("System.out.println(\"方法体前面\");");
m1.insertAfter("System.out.println($1);");
// 通过反射调用生成的方法
Class clazz = cc.toClass();
Emp emp = (Emp) clazz.newInstance();
Method method = clazz.getDeclaredMethod("sayHello", new Class[] { String.class });
method.invoke(emp, "张三");
} catch (Exception e) {
e.printStackTrace();
}
}
// 生成属性和方法
public static void test4(ClassPool pool, CtClass cc) {
try {
// CtField.make("private double salary;", cc);
CtField field = new CtField(CtClass.doubleType, "salary", cc);
field.setModifiers(Modifier.PRIVATE);
cc.addField(field);
// cc.getDeclaredField("salary"); //获取属性
CtMethod method = CtNewMethod.getter("getSalary", field);
cc.addMethod(method);
CtMethod method2 = CtNewMethod.getter("setSalary", field);
cc.addMethod(method2);
} catch (Exception e) {
e.printStackTrace();
}
}
// 生成构造器
public static void test5(ClassPool pool, CtClass cc) {
try {
cc.defrost();
CtConstructor[] cs = cc.getConstructors();
for (CtConstructor c : cs) {
System.out.println(c.getLongName());
c.insertAfter("System.out.println(\"可以在构造器前后加代码\");");
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 注解操作
public static void test6(ClassPool pool, CtClass cc) {
try {
cc.defrost();
Object[] annotations = cc.getAnnotations();
Author author = (Author) annotations[0];
System.out.println("name:" + author.name() + ",year:" + author.year());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ClassPool pool = ClassPool.getDefault();
CtClass cc = null;
try {
cc = pool.get("com.gs.Emp");
} catch (NotFoundException e) {
e.printStackTrace();
}
test1(pool, cc);
//test2(pool, cc);
test3(pool, cc);
test5(pool, cc);
test6(pool, cc);
}
}