字节码类库之Javassist

Javassist优势

– 比反射开销小,性能高。
–javassist性能高于反射,低于ASM
运行时操作字节码可以让我们实现如下功能:
– 动态生成 新的类
– 动态改变某个类的结构 ( 添加 / 删除 / 修改 新的属性 / 方法 )
javassist 的最外层的 API 和 JAVA 的反射包中的 API 颇为 类似 。
它 主要 由 CtClass , CtMethod, ,以及 CtField 几个类组成。用以执行和 JDK 反射 API 中 java.lang.Class, java.lang.reflect.Method, java.lang.reflect.Method .Field 相同的 操作 。
方法操作
– 修改已有方法的方法体(插入代码到已有方法体)
– 新增方法 删除方法


javassist的局限性
JDK5.0 新语法不支持 ( 包括泛型、枚举 ) ,不支持注解修改,但可以通过底层的 javassist 类来解决,具体参考: javassist.bytecode.annotation
不支持数组的初始化,如 String[]{"1","2"} ,除非只有数组的容量为 1
不支持内部类和匿名类
不支持 continue 和 break表达式。
对于继承关系,有些不支持。例如
class A {}  
class B extends A {} 
class C extends B {} 

 

创建类:

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewConstructor;

public class App {

    public static void main(String[] args) throws Exception {
        // 利用javassist 创建类

        ClassPool poll = ClassPool.getDefault();
        // 创建类名 全路径
        CtClass ctClass = poll.makeClass("com.hella.thread.jvm.javassist.User");
        // 创建属性
        CtField name = CtField.make("private String name;", ctClass);
        CtField age = CtField.make("private String age;", ctClass);

        // 属性添加到类中
        ctClass.addField(name);
        ctClass.addField(age);

        // 创建get set 方法
        CtMethod getName = CtMethod.make("public void getName(){return name;}", ctClass);
        CtMethod setName = CtMethod.make("public void setName(String name) {this.name = name;}", ctClass);
        CtMethod getAge = CtMethod.make("public String getAge() {return age;}", ctClass);
        CtMethod setAge = CtMethod.make("public void setAge(String age) {this.age = age;}", ctClass);

        // 方法添加到类中
        ctClass.addMethod(getName);
        ctClass.addMethod(setName);
        ctClass.addMethod(getAge);
        ctClass.addMethod(setAge);

        // 创建构造方法
        CtConstructor constructor = CtNewConstructor
                .make("public User(String name, String age) { this.name = name;this.age = age;}", ctClass);

        ctClass.addConstructor(constructor);

        // 生成的位置
        ctClass.writeFile("C:/Users/caich5/Desktop/test");
    }

}

修改类的信息

public class User {

    private String name;

    private String age;

    // 通过字节码技术,在这个类添加以下的方法

    // public int calcute(int a,int b){
    // return a + b;
    // }

}

修改并且执行:

import java.lang.reflect.Method;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public class Test {
    public static void main(String[] args) throws Exception {

        ClassPool poll = ClassPool.getDefault();
        // 获取到class
        CtClass ctClass = poll.get("com.hella.thread.jvm.javassist.User");
        CtMethod ctMethod = CtMethod.make("public int calcute(int a,int b){ return a + b ;}", ctClass);
        ctClass.addMethod(ctMethod);
        ctClass.writeFile("C:/Users/caich5/Desktop/test");

        // 使用反射执行
        Class<?> clazz = ctClass.toClass();
        Object newInstance = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("calcute", int.class, int.class);
        Object res = method.invoke(newInstance, 1, 2);
        System.out.println(res);

        // 需要添加的方法 也可以这样写
        // CtMethod m = new CtMethod(CtClass.intType, "add", new CtClass[] {
        // CtClass.intType, CtClass.intType },
        // userClass);
        // // 方法权限
        // m.setModifiers(Modifier.PUBLIC);
        // // 方法体内容
        // m.setBody("{System.out.println(\"Test003\"); return $1+$2;}");
    }

}

 

posted @ 2019-07-03 20:32  Chris,Cai  阅读(847)  评论(0编辑  收藏  举报