常见的字节码操作类库 Javassist

Java动态性常见的两种方式

反射、字节码操作

Java常见的字节码操作类库

BCEL、ASM、CGLIB(Code Generation Library)、Javassist

 

Javassist

  一个开源的分析、编辑和创建 Java 字节码 的类库 。性能较 ASM 差,跟 cglib 差不多,但是使用简单。很多开源框架都在使用它 

 主页

 http://www.csg.ci.i.u-tokyo.ac.jp/~ chiba/javassist /

javassist的 优势

 比反射开销小,性能高。

javassist性能高于反射,低于ASM

 运行时操作字节码可以让我们实现如下功能

 动态生成 新的类

 动态改变某个类的结构 ( 添加 / 删除 / 修改    新的属性 / 方法 )

javassist 的最外层的 API  JAVA 的反射包中的 API 颇为 类似 

 主要 由 CtClass  CtMethod, ,以及 CtField 几个类组成。用以执行和 JDK 反射 API 中 java.lang.Class java.lang.reflect.Method, java.lang.reflect.Method .Field 相同的 操作 

方法操作

 修改已有方法的方法体(插入代码到已有方法体)

 新增方法   删除方法

javassist的局限性

JDK5.0 新语法不支持 ( 包括泛型、枚举 ) ,不支持注解修改,但可以通过底层的 javassist 类来解决,具体参考: javassist.bytecode.annotation
支持数组的初始化,如 String[]{"1","2"} ,除非只有数组的容量为 1
支持内部类和匿名类
支持 continue  btreak 表达式。
对于继承关系,有些不支持。例如
class A {}  
class B extends A {} 
class C extends B {} 


要使用javassist需要下载javassiat压缩包。

解压之后发现javassist.jar ,工程中添加java build path 加入javassist.jar 。


========================================

生成一个新类。

package com.lgd.JavaAssist;

import java.io.IOException;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;

/**
 * 测试使用javaassist生成一个新的类
 * @author liguodong
 *
 */
public class Demo01 {
    public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException
    {
        ClassPool pool = ClassPool.getDefault();
        //要创建的类
        CtClass cc = pool.makeClass("com.lgd.bean.Emp");
        //创建属性
        CtField f1 = CtField.make("private int empno;", cc);
        CtField f2 = CtField.make("private String ename;", cc);
        cc.addField(f1);
        cc.addField(f2);
        //创建方法
        CtMethod cm1 = CtMethod.make("public int getEmpno(){return empno;}", cc);
        CtMethod cm2 = CtMethod.make("public void  setEmpno(int empno){this.empno = empno;}", cc);
        cc.addMethod(cm1);
        cc.addMethod(cm2);
        
        //添加构造器
        CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType,pool.get("java.lang.String")}, cc);
        constructor.setBody("{this.empno = empno;this.ename = ename;}");
        cc.addConstructor(constructor);
        cc.writeFile("/usr/Code/JavaCode");
        System.out.println("生成类,成功!");
    }
} 



========================================

在已有类的基础上动态增加属性,方法等。

package com.bjsxt.test;
public @interface Author 
{ 
	String name(); 
	year();
}


package com.lgd.JavaAssist;
@Author(name="chiba",year=2005)
public class Emp {
    private  int empno;
    private String ename;
    
    public void sayHello(int a)
    {
        System.out.println("sayHello,"+a);
    }
    
    public int getEmpno() {
        return empno;
    }
    public void setEmpno(int empno) {
        this.empno = empno;
    }
    public String getEname() {
        return ename;
    }
    public void setEname(String ename) {
        this.ename = ename;
    }
    public Emp(int empno, String ename) {
        super();
        this.empno = empno;
        this.ename = ename;
    }
    public Emp() {
        // TODO Auto-generated constructor stub
    }
}



package com.lgd.JavaAssist;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;

public class Demo02 {
    
    public static void Test01()throws Exception 
    {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("com.lgd.JavaAssist.Emp");
        byte[] bytes = cc.toBytecode();
        System.out.println(Arrays.toString(bytes));
        System.out.println(cc.getName());//获得类名
        System.out.println(cc.getSimpleName());//获得简要类名
        System.out.println(cc.getSuperclass());//获得父类
        System.out.println(cc.getInterfaces());//获得接口
        
    }
    //测试 产生新的方法
    public static void Test02() throws Exception
    {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("com.lgd.JavaAssist.Emp");
        //CtMethod m = CtNewMethod.make("public int add(int a,int b){return a+b;}", cc);
        CtMethod m = new CtMethod(CtClass.intType,"add",new CtClass[]{CtClass.intType,CtClass.intType},cc);        
        m.setModifiers(Modifier.PUBLIC);
        //$0代表this,$1代表第一个参数,$2代表第二个参数,$N代表第N个参数
        m.setBody("{System.out.println(\"Hello\");return $1+$2;}");
        
        cc.addMethod(m);
        //通过反射调用新生成的方法
        Class clazz = cc.toClass();
        Object obj = clazz.newInstance();//通过调用Emp无参构造器创建新的Emp对象
        
        Method method = clazz.getDeclaredMethod("add", int.class,int.class);
        Object result = method.invoke(obj,200,300);
        System.out.println(result);
        
    }
    //修改已有方法的信息,修改方法体的内容。
    public static void Test03() throws Exception
    {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("com.lgd.JavaAssist.Emp");
        CtMethod cm = cc.getDeclaredMethod("sayHello",new CtClass[]{CtClass.intType});
        //在方法体前面添加代码
        cm.insertBefore("System.out.println($1);System.out.println(\"start!!!\");");
        //在某一行添加代码
        cm.insertAt(9, "int b = 3;System.out.println(\"b=\"+b); ");
        //在方法体后面添加代码
        cm.insertAfter("System.out.println(\"end!!!\");");
        //通过反射调用新生成的方法
        Class clazz = cc.toClass();
        Object obj = clazz.newInstance();//通过调用Emp无参构造器创建新的Emp对象
        
        Method method = clazz.getDeclaredMethod("sayHello", int.class);
        Object result = method.invoke(obj,300);
        System.out.println(result);//因为没有返回值,所以为null。
    }
    //属性的操作
    public static void Test04() throws Exception
    {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("com.lgd.JavaAssist.Emp");
        //CtField f1 = CtField.make("private int salary", cc);
        CtField f1 = new CtField(CtClass.intType,"salary",cc);
        f1.setModifiers(Modifier.PRIVATE);
        cc.addField(f1);
        
        //cc.getDeclaredField("salary");//获取指定属性
        
        //增加相应的set和get方法
        cc.addMethod(CtNewMethod.getter("getSalary", f1));
        cc.addMethod(CtNewMethod.getter("setSalary", f1));
        
    }
    //构造方法的操作
    public static void Test05() throws Exception
    {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("com.lgd.JavaAssist.Emp");
        
        CtConstructor[] cs = cc.getConstructors();
        for(CtConstructor c : cs)
        {
            System.out.println(c.getName());
        }
        
    }
    //注解
    public static void Test06() throws Exception
    {
        CtClass cc = ClassPool.getDefault().get("com.lgd.JavaAssist.Emp");
        Object[] all = cc.getAnnotations();
        Author a = (Author)all[0];
        String name = a.name();
        int year = a.year();
        System.out.println("name:"+name+", year:"+year);
    }
    public static void main(String[] args) throws Exception{
        //Test01();
        //Test02();
        //Test03();
        //Test04();
        //Test05();
        Test06();
    }
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃果冻不吐果冻皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值