javassist动态生成class

来源:互联网 发布:淘宝国潮模特脖子纹身 编辑:程序博客网 时间:2024/05/29 18:06
 

什么是javassist?

Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。

关于java字节码的处理,目前有很多工具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解虚拟机指令,可以采用javassist。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类
 

联想

 由上可知,javassist 可以用来动态生成class文件,并且JVM可以直接加载生成的class文件。

具体作用:

设计一个对接系统,通过动态模型的增删改触发业务系统相应服务的调用。模型增删改方法动态发布为WebService服务。WebService服务采用CXF发布,动态类生成采用Javassist。由于WebService服务类需要添加WebService相关注解。

实战演练

从0开始实战,首先我们认识最初级的由javassist生成class类并且修改保存
package com.bsoft.javassis;import java.io.FileOutputStream;import java.io.IOException;import java.lang.reflect.Method;import javassist.CannotCompileException;import javassist.ClassPool;import javassist.CtClass;import javassist.CtConstructor;import javassist.CtField;import javassist.CtMethod;import javassist.CtNewMethod;import javassist.NotFoundException;public class TestJavassis {/** * @param args * @author yuzg * update time 2017-06-20 */public static void main(String[] args) {// TODO Auto-generated method stub/** * ClassPool是缓存CtClass对象的容器,所有的CtClass对象都在ClassPool中。 * 所以,CtClass对象很多时,ClassPool会消耗很大的内存,为了避免内存的消耗 * ,创建ClassPool对象时可以使用单例模式, * 或者对于CtClass对象,调用detach方法将其从ClassPool中移除 * 在ClassPool源码中getDefault 是单例模式生成 *  *  public static synchronized ClassPool getDefault() {        if (defaultPool == null) {            defaultPool = new ClassPool(null);            defaultPool.appendSystemPath();        }        return defaultPool;    } */ClassPool classpool =ClassPool.getDefault();//创建类名CtClass ctClass = classpool.makeClass("com.bsoft.esb.IEsbInvoker1");//ctClass.stopPruning(true);try {//添加属性        ctClass.addField(CtField.make("private int age;", ctClass));        //添加setAge方法        ctClass.addMethod(CtMethod.make("public void setAge(int age){this.age = age;}", ctClass));        ctClass.addMethod(CtMethod.make("public int getAge(){return this.age;}", ctClass));byte[] byteArray = ctClass.toBytecode();        FileOutputStream output = new FileOutputStream("D:\\IEsbInvoker1.class");        output.write(byteArray);                                                output.close();        /*** * 如果下面的判断和解冻方法不加会报错  * java.lang.RuntimeException: com.bsoft.esb.IEsbInvoker1 class is frozen * 原因解释如下: *  当CtClass对象通过writeFile()、toClass()、toBytecode()转化为Class后, *  Javassist冻结了CtClass对象,因此,JVM不允许再次加载Class文件,所以不允许对其修改。 */        if(ctClass.isFrozen()){ctClass.defrost();} ctClass = classpool.get("com.bsoft.esb.IEsbInvoker1");System.out.println(ctClass);CtField param = new CtField(classpool.get("java.lang.String"), "name", ctClass);   ctClass.addField(CtField.make("private java.lang.String sex;", ctClass));     ctClass.addField(CtField.make("private java.lang.String name;", ctClass));     ctClass.addMethod(CtNewMethod.setter("setName", param));       ctClass.addMethod(CtNewMethod.getter("getName", param));  //     // 添加无参的构造体  //        CtConstructor cons = new CtConstructor(new CtClass[] {}, ctClass);  //        cons.setBody("{name = \"Brant\";}");  //        ctClass.addConstructor(cons);       // 添加有参的构造体      CtConstructor   cons = new CtConstructor(new CtClass[] {classpool.get("java.lang.String")}, ctClass);          cons.setBody("{$0.name = $1;}");          ctClass.addConstructor(cons);      byteArray = ctClass.toBytecode();        output = new FileOutputStream("D:\\IEsbInvoker1.class");        output.write(byteArray);        output.close();        //ctClass转class后创建对象        Object o =ctClass.toClass().newInstance();        //这样写会报错:java.lang.ClassNotFoundException: com.bsoft.esb.IEsbInvoker1        /***         * 此时应该还在pool中         *///        Class.forName("com.bsoft.esb.IEsbInvoker1").newInstance();        //获取方法        Method methodSet = o.getClass().getMethod("setName", new Class[] {String.class});       //反射原理        methodSet.invoke(o, "Alen");                Method getter = o.getClass().getMethod("getName");        System.out.println("name:"+getter.invoke(o, null));} catch (NotFoundException e) {System.out.println(e.getMessage());// TODO Auto-generated catch blocke.printStackTrace();}catch (CannotCompileException e) {System.out.println(e.getMessage());e.printStackTrace();}catch (IOException e) {e.printStackTrace();}catch (Exception e) {e.printStackTrace();}}

$0, $1, $2, ...  代表的含义:

 $0代表的是this,$1代表方法参数的第一个参数、$2代表方法参数的第二个参数,以此类推,$N代表是方法参数的第N个。例如:  
setName(String Name){   $0.name=$1;}
相当于 this.name=Name;




分别查看两次保存文件前后的class 文件 可用debug断点
首次保存生成的class文件:
package com.bsoft.esb;public class IEsbInvoker1{  private int age;  public void setAge(int paramInt)  {    this.age = paramInt;  }  public int getAge()  {    return this.age;  }}

修改后:






输出:
name:Alen
一个class 文件就生成好了。并且通过java反射机制可以明显看出,和jvm主动调用class类中的方法并无两样。稍后上传jar包资源文件

javassist.jar下载路径:点击下载javassist

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 运动过度小腿疼怎么办 衣服潮湿有异味怎么办 家里潮湿有异味怎么办 婚检白带有问题怎么办 体检前小便了怎么办 高考有英文纹身怎么办 高考手上有纹身怎么办 来大姨妈婚检怎么办 高考体检转氨酶偏高怎么办 播音主持有纹身怎么办 高考体检补不了怎么办 辅警体检不合格怎么办 小儿听力筛查未过关怎么办 宝宝听力没过关怎么办 护士体检有乙肝怎么办 高考体检表填错怎么办 高考体检表没有下载怎么办 警校视力没过怎么办 凉鞋挂钩总是脱怎么办 特别害怕抛妇产怎么办 抛妇产害怕紧张怎么办 毕业体检有乙肝怎么办? 宝宝胸围偏小怎么办 入园体检不合格怎么办 油表不显示油量怎么办 上大学体检不过怎么办 军校体检没过怎么办 六次化疗后怎么办 宝宝肚子有蛔虫怎么办 肾综激素依赖怎么办 胎儿阴囊有积液怎么办 中考学生英语很差怎么办 中考考得很差怎么办 科学总是考不好怎么办 初三学生数学不好怎么办 初三学生语文不好怎么办 初三学生英语不好怎么办 初三学生学习不好怎么办? 客户说不考虑怎么办 单位体检有乙肝怎么办 厂里体检出乙肝怎么办