javassist使用

本文详细介绍了Javassist这个开源的Java字节码操作库,它是JBoss应用服务器项目的一部分。Javassist简化了字节码的编辑,允许开发者在不熟悉虚拟机指令的情况下,通过Java代码动态修改类和创建新类。文章提供了获取类信息、插入和修改方法、创建类属性及注解等示例,展示了Javassist的易用性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java bytecode engineering toolkit since 1999

Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由日本的 Shigeru Chiba 所创建的,它已加入了开放源代码 JBoss 应用服务器项目,通过使用 Javassist 对字节码操作为 JBoss 实现动态"AOP"框架。

关于java字节码的处理,目前有很多工具,如bcel,ASM。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解虚拟机指令,可以采用javassist。javassist是jboss的一个子项目,其主要的优点在于简单、快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
Javassist (Java Programming Assistant) makes Java bytecode manipulation simple. It is a class library for editing bytecodes in Java; it enables Java programs to define a new class at runtime and to modify a class file when the JVM loads it.
Javassist(Java Programming Assistant)使Java字节码操作变得简单。它是一个用于在Java中编辑字节码的类库;它使Java程序能够在运行时定义新类,并在JVM加载时修改类文件。
1.javassist 获取类的基本信息

ClassPool classPool = ClassPool.getDefault();
        CtClass ctClass = classPool.get("org.example.domain.Student");
        //得到字节码
        byte[] bytes = ctClass.toBytecode();
        //获取长度
        System.out.println(bytes.length);
        //获取类名
        System.out.println(ctClass.getName());
        //获取简要类名
        System.out.println(ctClass.getSimpleName());
        //获取父类
        System.out.println(ctClass.getSuperclass().getName());
        //获取接口
        System.out.println(Arrays.toString(ctClass.getInterfaces()));
        //获取构造方法
        for(CtConstructor ctConstructor : ctClass.getConstructors()){
            System.out.println("构造方法 "+ctConstructor.getName());
        }
        //获取方法
        for(CtMethod ctMethod : ctClass.getMethods()){
            System.out.println("所有方法:"+ctMethod.getName());
        }

        for(CtMethod ctMethod : ctClass.getDeclaredMethods()){
            System.out.println("定义方法:"+ctMethod.getName());
        }

        for(CtField ctField : ctClass.getDeclaredFields()){
            System.out.println("定义属性:"+ctField.getName());
            System.out.println("属性类型:"+ctField.getType());
        }

2.在原有的方法后面添加自己定义的

ClassPool classPool = ClassPool.getDefault();
        CtClass ctClass = classPool.get("org.example.domain.Student");
        CtMethod ctMethod = ctClass.getDeclaredMethod("sayHello");
        ctMethod.insertBefore("System.out.println(\"调用前1\");");
        ctMethod.insertAt(20094, "System.out.println(\"在指定行插入代码\");");//貌似行号胡乱写也可以
        ctMethod.insertAfter("{" + "System.out.println(\"你好:\" + this.getName()+\",今年:\"+this.getAge());" + "}");
        Class newClass = ctClass.toClass();
        Student student = (Student) newClass.newInstance();
        student.setName("张三");
        student.setAge(18);
        student.sayHello();

注意,如果使用 JDK9 以下的JDK ,同时使用 3.20.0-GA 以上版本的 Javassist,调用 toClass 方法会报 StackWalker 异常
3.javassist 在声明的方法中重新定义内容

ClassPool classPool = ClassPool.getDefault();
        CtClass ctClass = classPool.get("org.example.domain.Student");
        CtMethod ctMethod = ctClass.getDeclaredMethod("hello",new CtClass[]{classPool.get("java.lang.String")});
        ctMethod.setBody("{" + "System.out.println(\"你好:\" + $1);" + "}");
        //ctClass.writeFile("C:\\installsoft\\");
        //加载修改后的类,注意:必须保证调用前此类未加载
        ctClass.toClass();
        new Student().hello("包青天");```
4.javassist 创建类 属性 方法 构造器 注解

ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.makeClass(“org.example.domain.User”);

   //创建属性
    ctClass.addField(CtField.make("private int id;",ctClass));
    ctClass.addField(CtField.make("private String name;",ctClass));

    CtField ctField = new CtField(CtClass.intType,"age",ctClass);
    ctField.setModifiers(Modifier.PRIVATE);
    ctClass.addField(ctField);
    ctClass.addMethod(CtNewMethod.getter("getAge",ctField));
    ctClass.addMethod(CtNewMethod.setter("setAge",ctField));



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

    //创建方法
    CtClass[] ctClasses = new CtClass[]{CtClass.intType};
    // 返回值,方法名,参数,对象
    CtMethod ctMethod = new CtMethod(CtClass.intType,"setId",ctClasses,ctClass);
    //访问范围
    ctMethod.setModifiers(Modifier.PUBLIC);
    //方法体
    ctMethod.setBody("{return  $1;}");
    ctClass.addMethod(ctMethod);

    //添加注解
    ClassFile classFile = ctClass.getClassFile();
    ConstPool constPool = classFile.getConstPool();

    AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool,AnnotationsAttribute.visibleTag);
    //创建要添加的注解
    Annotation annotation = new Annotation(SerializedName.class.getCanonicalName(),constPool);
    //设置注解中的属性和值
    annotation.addMemberValue("value",new StringMemberValue("p",constPool));
    //把这个注解添加到AnnotationsAttribute对象里面
    annotationsAttribute.addAnnotation(annotation);
    //把这个对象放到要打上注解的字段/类上
    ctField.getFieldInfo().addAttribute(annotationsAttribute);
    //添加构造器
    CtConstructor ctConstructor = new CtConstructor(new CtClass[]{ CtClass.intType,classPool.get("java.lang.String")},ctClass);
    ctConstructor.setBody("{this.id = id;this.name = name;}");
    ctClass.addConstructor(ctConstructor);

    ctClass.writeFile("C:\\installsoft\\springbootdisruptor\\src\\main\\java");

Javassist 是一个用于操作 Java 字节码的强大库,允许开发者在运行时动态地修改类文件或创建新的类。它比直接使用 JVM 的字节码指令更简单易用,并且功能非常强大。 以下是 Javassist 常见的一些使用场景及步骤: ### 1. 添加依赖 如果你使用 Maven 构建项目,则需要添加以下依赖项到 `pom.xml` 文件: ```xml <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.28.0-GA</version> </dependency> ``` ### 2. 创建新类 你可以通过 Javassist 动态生成一个新的类: ```java ClassPool pool = ClassPool.getDefault(); CtClass ctClass = pool.makeClass("com.example.MyDynamicClass"); ctClass.writeFile(); // 将生成的 .class 写入磁盘 ``` 上述代码会生成名为 MyDynamicClass 的类并将其保存为 `.class` 文件。 ### 3. 修改现有类的方法 假设你想修改现有的某个方法内容,可以这样做: ```java ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.example.ExistingClass"); // 获取指定名称的方法 CtMethod method = cc.getDeclaredMethod("methodName"); method.setBody("{ System.out.println(\"Modified Method!\"); }"); cc.toClass(); // 应用更改后的类定义 ``` 这里我们将 ExistingClass 类中的 methodName 方法体替换成了打印字符串的操作。 ### 4. 实现接口、构造函数等高级特性 除了简单的增删改查外,还可以完成诸如实现接口、新增字段等功能: ```java // 新增字段 CtField field = new CtField(pool.get("int"), "myNewField", clazz); clazz.addField(field); // 绑定匿名内部类实例化表达式给变量 this$0 (适用于外部类访问) ctor.setBody("{ $0.this$0 = $1; }"); ``` 以上只是对 Javassist 使用的一个简略概述,实际应用中可以根据需求深入研究更多细节。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值