学习笔记——JAVA字节码操作 Javassist的用法

时间:2021-10-24 17:09:13

功能
动态生成新的类
动态改变某个类的结构(增删改查 新的属性和方法)

优势
比反射开销小
javaAasist性能高于反射低于ASM

常见的类库
BCEL
ASM
CGLIB
Javassist//下载地址http://jboss-javassist.github.io/javassist/
学习笔记——JAVA字节码操作 Javassist的用法

javassist主要有CtClass,CtMethod,CtFile。用于执行和jdk反射API中的java.lang.Class,java.lang.reflect.Method,java.lang.reflect.Method.Field相同的操作

创建一个类

package study;

import java.io.IOException;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;

/** * 测试javassist生成一个新的类 * * @author http://blog.csdn.net/thewaiting * */
public class Text {
    public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.makeClass("study2.Person");

        // 创建属性
        CtField f = CtField.make("private int id;", cc);
        CtField f2 = CtField.make("private String name;", cc);
        cc.addField(f);
        cc.addField(f2);

        // 创建方法
        CtMethod m = CtMethod.make("public int getId(){return this.id;}", cc);
        CtMethod m2 = CtMethod.make("public void setId(int id){this.id = id;}", cc);
        cc.addMethod(m);
        cc.addMethod(m2);

        // 添加构造器
        CtConstructor c = new CtConstructor(new CtClass[] { CtClass.intType, pool.get("java.lang.String") }, cc);
        // 构造方法体
        c.setBody("{this.id = id;this.name = name;}");
        cc.addConstructor(c);
        // 放入工作空间
        cc.writeFile("D:/text");
        System.out.println("生成的类用反编译工具查看");
    }
}

获取一个类

package study;

public class Person {
    private int id;
    private String name;
    public Person() {   
    }

    public Person(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

javassist的用法

package study;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AllPermission;
import java.util.Arrays;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMember;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.Modifier;
import javassist.NotFoundException;

/** * * 测试javassist的api * * @author http://blog.csdn.net/thewaiting * */
public class Text {
    /** * 处理类的基本用法 * * @throws NotFoundException * @throws CannotCompileException * @throws IOException */
    public static void text1() throws NotFoundException, IOException, CannotCompileException {
        // 获得池对象
        ClassPool pool = ClassPool.getDefault();
        // 获得指定某个类
        CtClass cc = pool.get("study.Person");
        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());// 获得父类
    }

    /** * 测试产生新的方法 * * @throws NotFoundException * @throws CannotCompileException * @throws IllegalAccessException * @throws InstantiationException * @throws SecurityException * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalArgumentException */
    public static void text2()
            throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException,
            NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        // 获得池对象
        ClassPool pool = ClassPool.getDefault();
        // 获得指定某个类
        CtClass cc = pool.get("study.Person");

        // CtMember m = CtNewMethod.make("public int add(int a,int b){return
        // a+b}", cc);
        // 参数 指定返回类型 方法的名称 方法的参数
        CtMember m = new CtMethod(CtClass.intType, "add", new CtClass[] { CtClass.intType, CtClass.intType }, cc);
        // 是什么方法
        m.setModifiers(Modifier.PUBLIC);
        ((CtBehavior) m).setBody("{return $1+$2;}");// $0 为this $后为形参
        cc.addMethod((CtMethod) m);
        // 通过反射调用新生成的方法
        Class clazz = cc.toClass();
        Object obj = clazz.newInstance();// 通过调用person无参构造,创建新的person对象
        Method method = clazz.getDeclaredMethod("add", int.class, int.class);
        System.out.println(method.invoke(obj, 200, 300));
    }

    /** * 修改方法已经有的信息 * * @throws NotFoundException * @throws CannotCompileException * @throws NoSuchMethodException * @throws SecurityException * @throws InstantiationException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException */
    public static void text3()
            throws NotFoundException, CannotCompileException, NoSuchMethodException, SecurityException,
            InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        // 获得池对象
        ClassPool pool = ClassPool.getDefault();
        // 获得指定某个类
        CtClass cc = pool.get("study.Person");

        CtMethod cm = cc.getDeclaredMethod("say", new CtClass[] { CtClass.intType });// 第二个参数为数组
        // 修改方法 在方法前加 在方法的第几行加 在方法后面加
        cm.insertBefore("System.out.println($1+\" start\");");
        cm.insertAt(8, "int b = 3;System.out.println(b);");
        cm.insertAfter("System.out.println($1+\" end\");");

        // 通过反射调用新生成的方法
        Class clazz = cc.toClass();
        Object obj = clazz.newInstance();
        Method m = clazz.getDeclaredMethod("say", int.class);
        System.out.println(m.invoke(obj, 12));
    }

    /** * 属性的操作 * * @throws NotFoundException * @throws CannotCompileException */
    public static void text4() throws NotFoundException, CannotCompileException {
        // 获得池对象
        ClassPool pool = ClassPool.getDefault();
        // 获得指定某个类
        CtClass cc = pool.get("study.Person");

        // CtField field = CtField.make("private int id;", cc);
        CtField f1 = new CtField(CtClass.intType, "age", cc);
        f1.setModifiers(Modifier.PRIVATE);
        // 加上值
        cc.addField(f1, "10");

        // 获取值
        // cc.getDeclaredField("name");
        // 增加get set 方法
        cc.addMethod(CtNewMethod.getter("getAge", f1));
        cc.addMethod(CtNewMethod.getter("setAge", f1));

    }

    /** * 构造方法的操作 * * @throws NotFoundException */
    public static void text5() throws NotFoundException {
        // 获得池对象
        ClassPool pool = ClassPool.getDefault();
        // 获得指定某个类
        CtClass cc = pool.get("study.Person");

        CtConstructor[] cs = cc.getConstructors();
        for (CtConstructor c : cs) {
            System.out.println(c.getLongName());
            //c.insertBefore("");添加方法
        }
    }
    public static void text6() throws NotFoundException, ClassNotFoundException {
        CtClass cc = ClassPool.getDefault().get("study.Person");
        Object[] all = cc.getAnnotations();
        Author a = (Author) all[0];
        String name = a.name();
        int year = a.year();
        System.out.println("name "+name + " year "+ year);
        //能进一步操作
    }

    public static void main(String[] args) throws NotFoundException, IOException, CannotCompileException,
            InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException,
            IllegalArgumentException, InvocationTargetException, ClassNotFoundException {
        // text01();
        // text2();
        // text3();
        // text4();
        // text5();
        text6();
    }
}

学习笔记——JAVA字节码操作 Javassist的用法
学习笔记——JAVA字节码操作 Javassist的用法