Java之Javassist对类的常用操作小结-yellowcong

来源:互联网 发布:深圳24小时营业 知乎 编辑:程序博客网 时间:2024/06/08 01:50

用Javassit完了一段时间,感觉挺牛逼的,可以轻松的操作java的字节码文件,这个东西相当于ASM是轻松不少了,对了记得获取已存在类对象的时候,通过类名称com.yellowcong.test.User来获取,而不是通过类对象来获取,因为通过类对象来获取,就会导致加载了两个不同版本的类在JVM中,就会报错,当CtClass 调用writeFile()、toClass()、toBytecode() 这些方法的时候,Javassist会冻结CtClass Object,对CtClass object的修改将不允许。

创建类对象

可以通过javassit来动态创建类文件,然后使用类文件对象,动态添加字段,set,get方法,以及添加自定义方法,

/** * 通过javassist 来自己创建类对象 *  * @throws Exception */public static void testCreateObject() throws Exception {    ClassPool pool = ClassPool.getDefault();    // 创建类    CtClass ctclazz = pool.makeClass("com.yellowcong.test.User");    // 创建属性 String 类型的数据不是基本数据类型,所以不能通过CtClass获取    CtField usernameField = new CtField(pool.get(String.class.getName()), "username", ctclazz);    // 添加set和get方法    ctclazz.addMethod(CtNewMethod.setter("setUsername", usernameField));    ctclazz.addMethod(CtNewMethod.getter("getUsername", usernameField));    ctclazz.addField(usernameField);    // 添加int类型的数据    CtField ageField = new CtField(CtClass.intType, "age", ctclazz);    // 添加set和get方法    ctclazz.addMethod(CtNewMethod.setter("setAge", ageField));    ctclazz.addMethod(CtNewMethod.getter("getAge", ageField));    ctclazz.addField(ageField);    // 添加构造器,不带参数的    CtConstructor con = new CtConstructor(null, ctclazz);    con.setModifiers(Modifier.PUBLIC);    con.setBody("{System.out.println('init constructor');}");    ctclazz.addConstructor(con);    // 添加构造器,带参数的    CtConstructor con2 = new CtConstructor(new CtClass[] { pool.get(String.class.getName()), CtClass.intType },            ctclazz);    con2.setModifiers(Modifier.PUBLIC);    con2.setBody("{this.username = $1;this.age = $2;}");    ctclazz.addConstructor(con2);    // 添加方法    CtMethod say = new CtMethod(CtClass.voidType, "say", null, ctclazz);    say.setModifiers(Modifier.PUBLIC);    say.setBody("{System.out.print(\"我是\"+this.username+\",今年\"+this.age+\"岁\");}");    ctclazz.addMethod(say);    Class<?> clz = ctclazz.toClass();    // 获取构造器,实例化对象    Object obj = clz.getConstructor(String.class, int.class).newInstance("yellowcong", 18);    // 获取动态添加的方法    clz.getMethod("say", null).invoke(obj, null);    // 设定用户名称    clz.getMethod("setUsername", String.class).invoke(obj, "doubi");    Object ret = clz.getMethod("getUsername", null).invoke(obj, null);    System.out.println(ret.toString());}

更改以存在对象的类方法

在已有类的基础上,添加方法

/**     * 更改类结构已经存在的方法     * 在已有类的基础上,添加aop类似的操作,但是没有用到javassist的代理操作     * @throws Exception     */    public static void changeClsMethod() throws Exception {        ClassPool pool = ClassPool.getDefault();        CtClass cls = pool.get("com.yellowcong.test.TestDemo");        // 获取到所有的字段        CtField[] fields = cls.getFields();        for (CtField field : fields) {            System.out.println(field.getName());        }        // 对于String类型,CtClass中,没有这个数据类型,只有基本的8中数据类型        CtMethod method = cls.getDeclaredMethod("say", new CtClass[] { pool.get("java.lang.String") });        // 复制方法        CtMethod newMethod = CtNewMethod.copy(method, cls, null);        // 修改原来方法的名称        String methodName = method.getName() + "$Impl";        method.setName(methodName);        // 这个 inertBefore方法没有问题        // method.insertBefore("System.out.println($1);say($$);System.out.println(\"start!!!\");");        // insertAfter方法有问题        // method.insertAfter("System.out.println(\"end!!!\");");        // 修改方法体        // method.setBody("System.out.println(\"你没机会了\");");        // 修改原方法        newMethod.setBody("{System.out.println(\"执行前\");" + methodName + "($$);System.out.println(\"执行后\");}");        cls.addMethod(newMethod);        Class<?> me = cls.toClass();        Object obj = me.newInstance();        me.getDeclaredMethod("say", String.class).invoke(obj, "test");    }

修改类已存在的方法2

直接不要类以前的方法,然后直接覆盖,设定自己的方法体

    /**     * 修改类里面的方法     */    public static void changeMethodBody() throws Exception {        ClassPool pool = ClassPool.getDefault();        CtClass ctClazz = pool.get("com.yellowcong.test.TestDemo");        // 获取TestDemo里面的public void say(String name) 方法        CtMethod method = ctClazz.getDeclaredMethod("say", new CtClass[] { pool.get(String.class.getName()) });        //修改方法内容,这个方法已经存在,不用在添加了        method.setBody("{System.out.print(\"你是逗比\t\"+$1);}");        method.insertBefore("System.out.println(\"end!!!\");");        //对于inserAfter使用不了,具体是啥原因还不清楚        Class<?> clazz = ctClazz.toClass();        Object obj = clazz.newInstance();        clazz.getMethod("say", String.class).invoke(obj, "yellowcong");    }

完整的代码

package com.yellowcong.test;import java.lang.reflect.Constructor;import java.lang.reflect.Modifier;import javassist.CannotCompileException;import javassist.ClassPool;import javassist.CtClass;import javassist.CtConstructor;import javassist.CtField;import javassist.CtMethod;import javassist.CtNewMethod;import javassist.NotFoundException;/** * * 作者:yellowcong 日期:2017/09/01 時間:12:07:33 描述: */public class Demo10 {    public static void main(String[] args) throws Exception, NotFoundException {         changeMethodBody() ;    }    /**     * 修改类里面的方法     */    public static void changeMethodBody() throws Exception {        ClassPool pool = ClassPool.getDefault();        CtClass ctClazz = pool.get("com.yellowcong.test.TestDemo");        // 获取TestDemo里面的public void say(String name) 方法        CtMethod method = ctClazz.getDeclaredMethod("say", new CtClass[] { pool.get(String.class.getName()) });        //修改方法内容,这个方法已经存在,不用在添加了        method.setBody("{System.out.print(\"你是逗比\t\"+$1);}");        method.insertBefore("System.out.println(\"end!!!\");");        //对于inserAfter使用不了,具体是啥原因还不清楚        Class<?> clazz = ctClazz.toClass();        Object obj = clazz.newInstance();        clazz.getMethod("say", String.class).invoke(obj, "yellowcong");    }    /**     * 更改类结构已经存在的方法     * 在已有类的基础上,添加aop类似的操作,但是没有用到javassist的代理操作     * @throws Exception     */    public static void changeClsMethod() throws Exception {        ClassPool pool = ClassPool.getDefault();        CtClass cls = pool.get("com.yellowcong.test.TestDemo");        // 获取到所有的字段        CtField[] fields = cls.getFields();        for (CtField field : fields) {            System.out.println(field.getName());        }        // 对于String类型,CtClass中,没有这个数据类型,只有基本的8中数据类型        CtMethod method = cls.getDeclaredMethod("say", new CtClass[] { pool.get("java.lang.String") });        // 复制方法        CtMethod newMethod = CtNewMethod.copy(method, cls, null);        // 修改原来方法的名称        String methodName = method.getName() + "$Impl";        method.setName(methodName);        // 这个 inertBefore方法没有问题        // method.insertBefore("System.out.println($1);say($$);System.out.println(\"start!!!\");");        // insertAfter方法有问题        // method.insertAfter("System.out.println(\"end!!!\");");        // 修改方法体        // method.setBody("System.out.println(\"你没机会了\");");        // 修改原方法        newMethod.setBody("{System.out.println(\"执行前\");" + methodName + "($$);System.out.println(\"执行后\");}");        cls.addMethod(newMethod);        Class<?> me = cls.toClass();        Object obj = me.newInstance();        me.getDeclaredMethod("say", String.class).invoke(obj, "test");    }    /**     * 通过javassist 来自己创建类对象     *      * @throws Exception     */    public static void testCreateObject() throws Exception {        ClassPool pool = ClassPool.getDefault();        // 创建类        CtClass ctclazz = pool.makeClass("com.yellowcong.test.User");        // 创建属性 String 类型的数据不是基本数据类型,所以不能通过CtClass获取        CtField usernameField = new CtField(pool.get(String.class.getName()), "username", ctclazz);        // 添加set和get方法        ctclazz.addMethod(CtNewMethod.setter("setUsername", usernameField));        ctclazz.addMethod(CtNewMethod.getter("getUsername", usernameField));        ctclazz.addField(usernameField);        // 添加int类型的数据        CtField ageField = new CtField(CtClass.intType, "age", ctclazz);        // 添加set和get方法        ctclazz.addMethod(CtNewMethod.setter("setAge", ageField));        ctclazz.addMethod(CtNewMethod.getter("getAge", ageField));        ctclazz.addField(ageField);        // 添加构造器,不带参数的        CtConstructor con = new CtConstructor(null, ctclazz);        con.setModifiers(Modifier.PUBLIC);        con.setBody("{System.out.println('init constructor');}");        ctclazz.addConstructor(con);        // 添加构造器,带参数的        CtConstructor con2 = new CtConstructor(new CtClass[] { pool.get(String.class.getName()), CtClass.intType },                ctclazz);        con2.setModifiers(Modifier.PUBLIC);        con2.setBody("{this.username = $1;this.age = $2;}");        ctclazz.addConstructor(con2);        // 添加方法        CtMethod say = new CtMethod(CtClass.voidType, "say", null, ctclazz);        say.setModifiers(Modifier.PUBLIC);        say.setBody("{System.out.print(\"我是\"+this.username+\",今年\"+this.age+\"岁\");}");        ctclazz.addMethod(say);        Class<?> clz = ctclazz.toClass();        // 获取构造器,实例化对象        Object obj = clz.getConstructor(String.class, int.class).newInstance("yellowcong", 18);        // 获取动态添加的方法        clz.getMethod("say", null).invoke(obj, null);        // 设定用户名称        clz.getMethod("setUsername", String.class).invoke(obj, "doubi");        Object ret = clz.getMethod("getUsername", null).invoke(obj, null);        System.out.println(ret.toString());    }}
原创粉丝点击