javaassist简单运用以及动态操作字节码

本小节主要介绍字节码库javaassist的简单运用.javaassist类似于cglib,都能动态的操作字节码,动态的生成字节码文件(class文件).

一.创建maven工程,导入依赖

 <dependency>
          <groupId>org.javassist</groupId>
          <artifactId>javassist</artifactId>
          <version>3.23.1-GA</version>
 </dependency>

二.代码展示:

涉及的实体类:

package javaassist;

public class Boy {

    public void showSelf(){
        System.out.println("I'm  a handsome boy");
    }
}

测试类:

package javaassist;

import javassist.*;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class JavaAssistTest {

    public static void main(String[] args) throws CannotCompileException, IOException, NotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
		makeCtClass();
        dynamicModifyMethod();
    }

    /**
     * 生成一个类名为Girl的类文件 拥有old,name属性以及get,set方法
     * 拥有一个无参构造函数,和有参构造
     * public class Girl {
     int old;
     String name;
     public int getOld() {
     return this.old;}
     public void setOld(int var1) {
     this.old = var1;}
     public String getName() {
     return this.name;}
     public void setName(String var1) {
     this.name = var1;}
     public Girl() {}
     public Girl(int var1, String var2) {
     this.old = var1;
     this.name = var2;}
     *
     * @throws CannotCompileException
     * @throws IOException
     * @throws NotFoundException
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws InvocationTargetException
     */
    private static void makeCtClass() throws CannotCompileException, IOException, NotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException{
       //获取一个类池
        ClassPool pool = ClassPool.getDefault();

        //在类池中创建一个Girl的类文件
        CtClass girlCtClass = pool.makeClass("Girl");

        //创建一个old属性
        CtField oldField = new CtField(CtClass.intType, "old", girlCtClass);

        //将属性添加到Gril类文件中
        girlCtClass.addField(oldField);

        //创建一个name属性
        CtField nameField = new CtField(pool.get("java.lang.String"), "name", girlCtClass);

        //将name属性添加到Girl类文件中
        girlCtClass.addField(nameField);

        //生成属性old get方法
        CtMethod oldGetMethod = CtNewMethod.make("public int getOld(){return old;}", girlCtClass);

        //将get方法添加到Girl类文件中
        girlCtClass.addMethod(oldGetMethod);

        //生成属性old  set方法
        CtMethod oldSetMethod = CtNewMethod.make("public void setOld(int old){this.old = old;}", girlCtClass);

        //将set方法添加到Girl类文件中
        girlCtClass.addMethod(oldSetMethod);

        CtMethod nameGetMethod = CtNewMethod.make("public String getName(){return name;}", girlCtClass);
        girlCtClass.addMethod(nameGetMethod);
        CtMethod nameSetMethod = CtNewMethod.make("public void setName(String name){this.name = name;}", girlCtClass);
        girlCtClass.addMethod(nameSetMethod);

        //生成无参构造
        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, girlCtClass);
        //设置方法体
        ctConstructor.setBody("{}");
        //将构造方法添加到leiwenjian类文件
        girlCtClass.addConstructor(ctConstructor);

        //生成有参构造
        CtConstructor ctConstructor1 = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, girlCtClass);
        //设置方法体   $1 代表第一个参数  $2 代表第二个参数
        ctConstructor1.setBody("{this.old = $1; this.name = $2;}");
        girlCtClass.addConstructor(ctConstructor1);

        //指定文件目录,生成class文件  存在则覆盖
        girlCtClass.writeFile("src/main/test/javaassist");

        /**
         * 通过反射调用方法
         */
        //将CtClass 转化为 Class
        Class clazz = girlCtClass.toClass();
        Object obj = clazz.newInstance();
        Method setNameMethod = clazz.getDeclaredMethod("setName", String.class);
        setNameMethod.invoke(obj, "小芳");

        Method getNameMethod = clazz.getDeclaredMethod("getName");
        System.out.println(getNameMethod.invoke(obj));

        girlCtClass.detach();  //从类池中删除
    }

    /**
     * 事先创建一个类
     * package javaassist;
     public class Boy {
     public void showSelf(){
     System.out.println("I'm  a handsome boy");
     }
     }

     动态操作类的方法
     * @throws NotFoundException
     * @throws CannotCompileException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    private static void dynamicModifyMethod() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        //获取默认的类池
        ClassPool classPool = ClassPool.getDefault();

        //从已有的 获取ctclass文件
        CtClass boyCtClass = classPool.get("javaassist.Boy");

        //取得showSelf方法
        CtMethod showSelfCtMethod = boyCtClass.getDeclaredMethod("showSelf");
        //在方法体的内容前 插入
        showSelfCtMethod.insertBefore("{System.out.println(\"-----------方法开始执行---------\");}");
        //在方法体的内容后 插入
        showSelfCtMethod.insertAfter("System.out.println(\"-----------方法执行后----------\");");

        //转化为 Class 对象
        Class boyClass = boyCtClass.toClass();

        //通过反射调用showSelf方法
        Object boyObj = boyClass.newInstance();
        Method showSelfMethod = boyClass.getDeclaredMethod("showSelf");
        showSelfMethod.invoke(boyObj);
    }
}

makeclass()方法会在对应目录下生成Girl.class文件,可用反编译工具打开.
如图:`
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

public class Girl {
int old;
String name;

public int getOld() {
    return this.old;
}

public void setOld(int var1) {
    this.old = var1;
}

public String getName() {
    return this.name;
}

public void setName(String var1) {
    this.name = var1;
}

public Girl() {
}

public Girl(int var1, String var2) {
    this.old = var1;
    this.name = var2;
}

}
`
运行结果:
小芳

dynamicModifyMethod()方法会在showSelf()方法体执行前后插入代码:
运行结果:
-----------方法开始执行---------
I’m a handsome boy
-----------方法执行后----------

三.
在编译过程中动态操作class字节码文件,
看到这个就很好了解 cglib的aop编程了,有莫有

你可能感兴趣的:(java基础)