javassist使用

一.介绍

    Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。在dubbo生成代理对象默认就是使用的javassist。

二.使用

1.几个重要的类:

ClassPool : 一个基于HashMap实现的CtClass对象容器,其中键是类名称,值是表示该类的CtClass对象。默认的ClassPool使用与底层JVM相同的类路径,因此在某些情况下,可能需要向ClassPool添加类路径或类字节。

CtClass :表示一个类, 从ClassPool中获取

CtConstructor: 表示构造方法

CtMethod:表示方法

CtField:表示字段,属性

2.动态生成一个类

maven坐标:

<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.22.0-GA</version>
</dependency>
  ClassPool pool =ClassPool.getDefault();// 获取classpool
        // 创建类
        CtClass ctClass = pool.makeClass("com.laoxu.desgin.javassist.ProxyTest");
        ctClass.setInterfaces(new CtClass[]{pool.makeInterface("java.lang.Cloneable")}); // 实现某个接口
        //ctClass.setModifiers(); 设置 AccessFlag(public  , private 等)
        // ctClass.setSuperclass();  继承某个类
        try {
            // 创建一个字段     类型     字段名    类
            CtField id = new CtField(CtClass.intType, "id", ctClass);
            id.setModifiers(AccessFlag.PRIVATE);
            // 将字段添加到类中
            ctClass.addField(id);
            // 创建构造方法
            CtConstructor constructor = CtNewConstructor.make("public  ProxyTest (int id){this.id= id;}", ctClass);
            ctClass.addConstructor(constructor);
            // 创建method
            CtMethod method = CtNewMethod.make("public void  print(String str){System.out.println(str);}", ctClass);
            ctClass.addMethod(method);
            
            // 写出, 生成实体文件
            ctClass.writeFile();
            // 生成class对象
            //ctClass.toClass();
        } catch (CannotCompileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NotFoundException e) {
            e.printStackTrace();
        }

执行后,在idea里面就可以看到.class文件。

反编译后:

package com.laoxu.desgin.javassist;

public class ProxyTest implements Cloneable {
    public int id;

    public ProxyTest(int var1) {
        this.id = var1;
    }

    public void print(String var1) {
        System.out.println(var1);
    }
}

3.动态修改方法体

现在有一个PrintTest类,其中有个print方法,我们想要在print方法前添加某段代码,在print方法后添加某段代码。说白了就是实现AOP的效果。

public class PrintTest {


    public void print(String str){

        System.out.println(str);
    }
}

修改:

 ClassPool pool =ClassPool.getDefault();

        try {
            // 获取ctclass 对象
            CtClass ctClass = pool.getCtClass("com.laoxu.desgin.javassist.PrintTest");
            // 获取方法
            CtMethod printMethod = ctClass.getDeclaredMethod("print");
            // 添加前置
            printMethod.insertBefore("System.out.println(\"before\");");
            //添加后置
            printMethod.insertAfter("System.out.println(\"after\");");

            ctClass.writeFile();

            // 生成class对象
            Class clazz = ctClass.toClass();

            Object instance = clazz.newInstance();

            Method method = clazz.getMethod("print", String.class);
            // 反射执行
            method.invoke(instance,"2019-08");
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (CannotCompileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

后面我们对生成这个代理对象进行反射执行修改后的方法,得到结果:

before
2019-08
after

我们在看下生成的那个代理对象

package com.laoxu.desgin.javassist;

public class PrintTest {
    public PrintTest() {
    }

    public void print(String str) {
        System.out.println("before");
        System.out.println(str);
        Object var3 = null;
        System.out.println("after");
    }
}

猜你喜欢

转载自blog.csdn.net/yuanshangshenghuo/article/details/100169538