使用javassist动态注入代码

使用javassist动态注入代码

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

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

    假设,存在类A,如下:

package com;
public class A {
	 public void method() {
	        for (int i = 0; i < 1000000; i++) {
	        }
	        System.out.println("method1");
	    }
}
测试类B1如下:

package com;
public class B1 {
	public static void main(String[] args) {
        A a = new A();
        a.method();    
    }
}
现在想统计一下method的执行时间, 为了减少工作量,通过动态注入代码的形式来实现,B2类。
package com;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;
public class B2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		CtClass ctClass;
		try {
			// 用于取得字节码类,必须在当前的classpath中,使用全称
			ctClass = ClassPool.getDefault().get("com.A");
			// 需要修改的方法名称
			String mname = "method";
			CtMethod mold = ctClass.getDeclaredMethod(mname);
			// 修改原有的方法名称
			String nname = mname + "$impl";
			mold.setName(nname);
			
			// 创建新的方法,复制原来的方法
			CtMethod mnew = CtNewMethod.copy(mold, mname, ctClass, null);

			// 主要的注入代码
			StringBuffer body = new StringBuffer();
			body.append("{\nlong start = System.currentTimeMillis();\n");
			// 调用原有代码,类似于method();($$)表示所有的参数
			body.append(nname + "($$);\n");
			body.append("System.out.println(\"Call to method " + mname
					+ " took \" +\n (System.currentTimeMillis()-start) + "
					+ "\" ms.\");\n");

			body.append("}");
			// 替换新方法
			mnew.setBody(body.toString());
			// 增加新方法
			ctClass.addMethod(mnew);
			// 类已经更改,注意不能使用A a=new A();,因为在同一个classloader中,不允许装载同一个类两次
			A a = (A) ctClass.toClass().newInstance();
			a.method();
		} catch (NotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (CannotCompileException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {

		}
	}

}

这只是简单的一个应用。javassist还提供了很多的功能,用于更改类结构。




你可能感兴趣的:(ASM及字节码)