常见的字节码操作类库
https://github.com/jboss-javassist/javassist
JAVAssist的API详解
用javassist生成一个新的类
import javassist.*;
/**
* 测试用javassist生成一个新的类
*/
public class Demo01 {
public static void main(String[] args) throws Exception{
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 创建新类
CtClass cc = pool.makeClass("test.bean.Emp");
// 创建属性
CtField f1 = CtField.make("private int empno;", cc);
CtField f2 = CtField.make("private String ename;", cc);
cc.addField(f1);
cc.addField(f2);
// 创建方法
CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc);
CtMethod m2 = CtMethod.make("public void setEmpno(int empno){this.empno = empno;}", cc);
cc.addMethod(m1);
cc.addMethod(m2);
// 添加构造器
CtConstructor constructor = new CtConstructor(new CtClass[]{
CtClass.intType, pool.get("java.lang.String")}, cc);
constructor.setBody("{this.empno=empno; this.ename=ename;}");
cc.addConstructor(constructor);
cc.writeFile("./"); // 将上面创建好的类写入指定文件夹下
System.out.println("Successful !!!");
}
}
生成.class文件
找到字节码所在目录打开即可
JAVAssist库的API详解
test.Emp
package test;
public class Emp {
private int empno;
private String ename;
public void sayHello(int a){
System.out.println("sayHello " + a);
}
public int getEmpno() {
return empno;
}
public void setEmpno(int empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Emp(int empno, String ename) {
this.empno = empno;
this.ename = ename;
}
public Emp(){
}
}
Demo
package test;
import javassist.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 测试用javassist API
*/
public class Demo02 {
/**
* 处理类的基本用法
*/
public static void test01() throws Exception{
ClassPool pool = ClassPool.getDefault();
// 加载已有类
CtClass cc = pool.get("test.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()); // 获得接口,得到的是一个数组
}
/**
* 测试添加新的方法
*/
public static void test02() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Emp");
// CtMethod m = CtNewMethod.make("public int add(int a, int b){return a+b;}", cc);
// 声明一个方法
// (返回类型, 方法名, 参数类型, 添加到哪个类)
CtMethod m = new CtMethod(CtClass.intType, "add", new CtClass[]{
CtClass.intType, CtClass.intType}, cc);
// 添加方法体
m.setModifiers(Modifier.PUBLIC); // 访问权限
m.setBody("{System.out.println(\"add fun\"); return $1 + $2;}");
cc.addMethod(m);
// 通过反射调用新生成的方法
Class clz = cc.toClass();
Object obj = clz.getConstructor().newInstance(); // 创建Emp对象
Method method = clz.getDeclaredMethod("add", int.class, int.class);
Object result = method.invoke(obj, 200, 300);
System.out.println(result);
}
/**
* 修改已有方法的信息,修改方法体的内容
*/
public static void test03() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Emp");
CtMethod cm = cc.getDeclaredMethod("sayHello", new CtClass[]{
CtClass.intType});
cm.insertBefore("System.out.println($1); System.out.println(\"start !!!\");");
// 在原文件的指定行数添加代码
cm.insertAt(9, "int b = 3;System.out.println(\"b = \" + b);");
cm.insertAfter("System.out.println(\"end !!!\");");
// 通过反射调用新生成的方法
Class clz = cc.toClass();
Object obj = clz.getConstructor().newInstance(); // 创建Emp对象
Method method = clz.getDeclaredMethod("sayHello", int.class);
method.invoke(obj, 300);
}
/**
* 属性的操作
*/
public static void test04() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Emp");
// CtField f1 = CtField.make("private int salary = 1000;", cc);
CtField f1 = new CtField(CtClass.intType,"salary",cc);
f1.setModifiers(Modifier.PRIVATE);
cc.addField(f1, "1000");
// 增加相应的set/get方法
cc.addMethod(CtNewMethod.getter("getSalary", f1));
cc.addMethod(CtNewMethod.setter("setSalary", f1));
CtField f2 = cc.getDeclaredField("salary"); // 获取指定属性
System.out.println(f2.getName());
// 反射
Class clz = cc.toClass();
// Emp emp = (Emp)clz.getConstructor().newInstance();
Object emp = clz.getConstructor().newInstance();
Field sf = clz.getDeclaredField("salary");
sf.setAccessible(true); // 设置这个属性不需要做安全检查了,可以直接访问
System.out.println(sf.get(emp));
}
/**
* 构造器方法的操作
*/
public static void test05() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Emp");
CtConstructor[] cs = cc.getConstructors();
for (CtConstructor c: cs) {
System.out.println(c.getLongName());
// c.insertBefore(...);
}
}
public static void main(String[] args) throws Exception{
// test01(); // testXX 不能同时调用
// test02();
// test03();
// test04();
test05();
}
}
Output
test01
扫描二维码关注公众号,回复:
12657490 查看本文章

test02
test03
test04
test05