使用javassist动态注入代码

    关于java字节码的处理,目前有很多工具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解虚拟机指令,可以采用javassist。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
    下面通过一个简单的例子,通过javassist来实现如何动态注入代码。
    假设,存在类A,如下:
java 代码
 
  1. public class A {  
  2.     public void method() {  
  3.         for (int i = 0; i < 1000000; i++) {  
  4.         }  
  5.         System.out.println("method1");  
  6.     }  
  7. }  

测试类B如下:
java 代码
 
  1. public class B {  
  2.     public static void main(String[] args) {  
  3.         A a = new A();  
  4.         a.method();     
  5.     }  
  6. }  

现在想统计一下method的执行时间,
默认的实现是修改method:
 
java 代码
 
  1. public void method() {  
  2.         long start = System.currentTimeMillis();  
  3.         for (int i = 0; i < 1000000; i++) {  
  4.         }  
  5.         System.out.println("method1");  
  6.         long end = System.currentTimeMillis();  
  7.         System.out.println(end - start);  
  8.     }  

如果A的方法很多,统计方法的执行时间的代码就会相应的增加。为了减少工作量,通过动态注入代码的形式来实现。
修改B的main方法:
 
java 代码
 
  1. public static void main(String[] args) throws Exception {  
  2.     //用于取得字节码类,必须在当前的classpath中,使用全称  
  3.       CtClass ctClass = ClassPool.getDefault().get("org.esoft.A");  
  4.        //需要修改的方法名称  
  5.       String mname = "method";         
  6.       CtMethod mold = ctClass.getDeclaredMethod(mname);  
  7.        //修改原有的方法名称  
  8.       String nname = mname + "$impl";  
  9.       mold.setName(nname);  
  10.        //创建新的方法,复制原来的方法  
  11.       CtMethod mnew = CtNewMethod.copy(mold, mname, ctClass, null);  
  12.        //主要的注入代码  
  13.       StringBuffer body = new StringBuffer();  
  14.       body.append("{\nlong start = System.currentTimeMillis();\n");  
  15.       //调用原有代码,类似于method();($$)表示所有的参数  
  16.       body.append(nname + "($$);\n");  
  17.       body.append("System.out.println(\"Call to method "  
  18.                   + mname  
  19.                   + " took \" +\n (System.currentTimeMillis()-start) + "  
  20.                   + "\" ms.\");\n");  
  21.       
  22.       body.append("}");  
  23.        //替换新方法  
  24.       mnew.setBody(body.toString());  
  25.        //增加新方法  
  26.       ctClass.addMethod(mnew);  
  27.       //类已经更改,注意不能使用A a=new A();,因为在同一个classloader中,不允许装载同一个类两次  
  28.       A a=(A)ctClass.toClass().newInstance();  
  29.       a.method();  
  30.   }  

这只是简单的一个应用。javassist还提供了很多的功能,用于更改类结构。有兴趣的可以参考相关文档

你可能感兴趣的:(java,虚拟机,工作,jboss,tapestry)