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");