java字节码操作-Javassist库介绍

Java动态性的两种常见方式

-反射
-字节码操作:所谓字节码操作就是当xx.class文件被加载到虚拟机后,我们可以使用类库来操作这些字节码
  
运行时操作字节码可以让我们实现如下功能

-动态生成新的类
-动态改变某个类的结构(添加/删除/修改新的属性/方法
  
常见的字节码操作类库

  • BCEL

  • ASM

  • CGLIB(Code Generation Library)

  • Javassist

优势:

-比反射开销小,性能高。
-JAVAasist性能高于反射,低于ASM

Javassist使用

如果需要详细了解:可以下载框架
maven依赖jar包

简单使用

字节码不能操作对象,如果需要操作对象还需要借助反射
创建新类

public static void main(String[] args) throws Exception {
    //获得类池
    ClassPool aDefault = ClassPool.getDefault();
 
    //创建类的名字 可以指定包名 例如:com.lj.Dog
    CtClass ctClass = aDefault.makeClass("Dog");
 
    //添加属性(可以new CtField,和添加方法类似(在test01中提及))
    CtField public_int_age = CtField.make("public int age;", ctClass);
    CtField public_string_like= CtField.make("public String like;", ctClass);
    ctClass.addField(public_int_age);
    ctClass.addField(public_string_like);
 
    //添加方法
    CtMethod test = CtMethod.make("public void test(){System.out.println(\"添加成功\");}", ctClass);
    ctClass.addMethod(test);
 
    //添加构造器
    CtConstructor ctConstructor = new CtConstructor(new CtClass[]{CtClass.intType,aDefault.get("java.lang.String")}, ctClass);
    ctConstructor.setBody("{this.age=$1;this.like=$2;}");
    ctClass.addConstructor(ctConstructor);
 
    //开始创建一个Dog.class文件,可以指定Dog.class文件路径
    ctClass.writeFile();
}

操作已经存在的类
1、给存在的.class文件追加方法.让对象去执行这个方法

public static void test01(){
        try {
            ClassPool aDefault = ClassPool.getDefault();
            CtClass ctClass = aDefault.get("com.zy.Dog");
            //byte[] bytes = ctClass.toBytecode();
            //获取类名
            System.out.println(ctClass.getName());
            //获取简单类名
            System.out.println(ctClass.getSimpleName());
 
            //添加方法
            //CtMethod test1 = CtMethod.make("public void test(int a,int b){System.out.println(\"添加成功\");}", ctClass);
            //另一种添加方法的方式
            CtMethod ctMethod = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType,CtClass.intType}, ctClass);
            ctMethod.setModifiers(Modifier.PUBLIC);
            ctMethod.setBody("return $1+$2;");
            ctClass.addMethod(ctMethod);
 
            //通过反射调用方法
            Class<?> aClass = ctClass.toClass();
            Method test = aClass.getDeclaredMethod("add",int.class,int.class);
            //对象0可以是外部传递进来,此时test方法就是一个代理方法
            Object o = aClass.getConstructor().newInstance();
            Object invoke = test.invoke(o, 1,1);
            System.out.println(invoke);
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

2、通过字节码实现AOP编程(AOP为Aspect Oriented Programming的缩写,意为面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术)
此时test02必须是一个代理类的方法。我们将自己的对象通过test02传递进去

public static void test02(){
        try {
            ClassPool aDefault = ClassPool.getDefault();
            CtClass ctClass = aDefault.get("com.lj.Dog");
            CtMethod play = ctClass.getDeclaredMethod("play");
            //可以对已经存在的方法进行修改
            //play.setBody("System.out.println(\"Dog没有play\");");
            //执行方法之前可以执行其他的方法;
            play.insertBefore("System.out.println(\"Dog在吃东西\");");
             
            //反射执行该方法
            Class<?> aClass = ctClass.toClass();
            Method test = aClass.getDeclaredMethod("play");
            Object o = aClass.getConstructor().newInstance();
            Object invoke = test.invoke(o);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值