• 【转载】使用javassist动态注入代码


    关于java字节码的处理,目前有很多工具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解虚拟机指令,可以采用javassist。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
        下面通过一个简单的例子,通过javassist来实现如何动态注入代码。
        假设,存在类A,如下:
    public class A {
        public void method() {
            for (int i = 0; i < 1000000; i++) {
            }
            System.out.println("method1");
        }
    }
    测试类B如下:
    public class B {
        public static void main(String[] args) {
            A a = new A();
            a.method();    
        }
    }
    现在想统计一下method的执行时间,
    默认的实现是修改method:
     public void method() {
            long start = System.currentTimeMillis();
            for (int i = 0; i < 1000000; i++) {
            }
            System.out.println("method1");
            long end = System.currentTimeMillis();
            System.out.println(end - start);
        }
    如果A的方法很多,统计方法的执行时间的代码就会相应的增加。为了减少工作量,通过动态注入代码的形式来实现。
    修改B的main方法:
        public static void main(String[] args) throws Exception {
          //用于取得字节码类,必须在当前的classpath中,使用全称
            CtClass ctClass = ClassPool.getDefault().get("org.esoft.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();
        }
    这只是简单的一个应用。javassist还提供了很多的功能,用于更改类结构。有兴趣的可以参考相关文档

  • 相关阅读:
    mysql and与or连用时遇到的坑
    mysql : 使用不等于过滤null的问题
    Bio Nio demo
    线上服务器的cpu使用达到100%了,如何排查、定位和解决该问题?
    二叉查找树、平衡二叉树、B树、B+树、聚集索引、非聚集索引
    java实现折线图统计数据
    递归构造树
    python中获取json数组中的具体数值(调用百度AI返回的json数据)
    python中使用ajax回调函数限制
    python+flask框架——前后端数据传递
  • 原文地址:https://www.cnblogs.com/jacktu/p/1315203.html
Copyright © 2020-2023  润新知