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()); }}
阅读全文
0 0
- Java之Javassist对类的常用操作小结-yellowcong
- Java之Javassistの常用API-yellowcong
- Java之javassist实现自动代理-yellowcong
- HTML常用的jquery操作-yellowcong
- Solr之java操作集群 -yellowcong
- Oracle之表创建及常用操作-yellowcong
- Java之文件压缩工具类-yellowcong
- Java之字符串工具类-yellowcong
- Java之日期工具类-yellowcong
- Java之文件工具类-yellowcong
- Java之文件下载工具类-yellowcong
- Java之图片裁剪工具类-yellowcong
- Java之Json工具类-yellowcong
- Java之Luence工具类-yellowcong
- jquery 常用的对字符串进行操作的方法小结
- Java学习之动态编译--字节码操作--javassist类库
- Hadoop之Java通过URL操作HDFS-yellowcong
- javascript中对Date类型的常用操作小结
- $.post() 提交表单,$.get() 异步刷新页面
- VM虚拟机centos6.5安装nginx
- HTML表格,跨行、跨列
- Qt插件定义
- tensorflow使用gpu
- Java之Javassist对类的常用操作小结-yellowcong
- Spring Boot相关知识
- 下列代码之后的结果为()?
- REM手机屏幕适配
- jdbc连接数据库的7大步骤(以通过jdbc连接实现数据的插入、更新为例)
- Twitter_Snowflake生成主键代码
- EPON OLT网管系统的实现
- 破解 Navicat Premium 12
- NYOJ 303. 序号互换(数字/字符串处理+进制转换思想)