Java字节码框架 -- Javassist

Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态”AOP”框架。

关于java字节码的处理,目前有很多工具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解虚拟机指令,可以采用javassist。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。

下面我们就用使用Javassist来创建一个类,并调用其中的方法

package com.carlzone.dubbo.javassist;

import javassist.*;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Modifier;

public class CompilerByJavassist {

    public static void main(String[] args) throws Exception {
        // ClassPool: CtClass对象容器
        ClassPool pool = ClassPool.getDefault();

        // 通过ClassPool生成一个public的User类
        CtClass ctClass = pool.makeClass("com.carlzone.learn.javassist.User");


        // 添加属性
        // 1. 添加属性private int id;
        CtField idField = new CtField(pool.getCtClass("int"), "id", ctClass);
        idField.setModifiers(Modifier.PRIVATE);
        ctClass.addField(idField);

        // 2.添加属性private String username
        CtField nameField = new CtField(pool.get("java.lang.String"), "username", ctClass);
        nameField.setModifiers(Modifier.PRIVATE);
        ctClass.addField(nameField);

        // 添加setter/getter方法
        ctClass.addMethod(CtNewMethod.getter("getId", idField));
        ctClass.addMethod(CtNewMethod.setter("setId", idField));
        ctClass.addMethod(CtNewMethod.getter("getUsername", nameField));
        ctClass.addMethod(CtNewMethod.setter("setUsername", nameField));

        // 添加构造函数
        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
        // 添加构造函数方法体
        StringBuffer sb = new StringBuffer();
        sb.append("{\n").append("this.id = 27;\n").append("this.username=\"carl\";\n}");
        ctConstructor.setBody(sb.toString());
        ctClass.addConstructor(ctConstructor);

        // 添加自定义方法
        CtMethod printMethod = new CtMethod(CtClass.voidType, "print", new CtClass[]{}, ctClass);
        printMethod.setModifiers(Modifier.PUBLIC);
        StringBuffer printSb = new StringBuffer();
        printSb.append("{\nSystem.out.println(\"begin!\");\n")
                .append("System.out.println(id);\n")
                .append("System.out.println(username);\n")
                .append("System.out.println(\"end!\");\n")
                .append("}");
        printMethod.setBody(printSb.toString());
        ctClass.addMethod(printMethod);

        // 生成一个Class
        Class<?> clazz = ctClass.toClass();
        Object obj = clazz.newInstance();

        // 反射执行方法
        obj.getClass().getMethod("print", new Class[]{}).invoke(obj, new Object[]{});

        // 把生成的class写入到文件中
        byte[] byteArr = ctClass.toBytecode();
        FileOutputStream fos = new FileOutputStream(new File("D://User.class"));
        fos.write(byteArr);
        fos.close();

    }

}

我们来看一下创建这个对象的全部过程:

  • 声明对象的全类名
  • 创建field,并设置getter/setter方法
  • 创建对象的无参构造器
  • 创建自定义方法

其实这个过程就相当于我们手写了这样一个类,下面我们来运行一下这个类:

这里写图片描述

下面我们到D盘去用反编译工具看一下生成的Class文件。

这里写图片描述

最后需要特别注意的是:

  • Javassist不支持要创建或注入的类中存在泛型参数
  • Javassist对@类型的注解(Annotation)只支持查询,不支持添加或修改

参考文章/推荐阅读:

  1. 用 Javassist 进行类转换
  2. Javassist的官方网站
  3. javassist 学习笔记
  4. javassist学习
  5. Javassist学习总结
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值