码迷,mamicode.com
首页 > 编程语言 > 详细

java Instrument修改字节码实现aop功能

时间:2017-08-10 20:57:49      阅读:248      评论:0      收藏:0      [点我收藏+]

标签:pen   tcl   rac   安全   dem   jar   cat   setname   declared   

 

Agent工程2个类:

public class MyAgent {
    
     /**
     * 该方法在main方法之前运行,与main方法运行在同一个JVM中
     * 并被同一个System ClassLoader装载
     * 被统一的安全策略(security policy)和上下文(context)管理
     */
    public static void premain(String agentOps, Instrumentation inst) {
        System.out.println("=========premain方法执行========");
        System.out.println(agentOps);
        // 添加Transformer
        inst.addTransformer(new MyTransformer());
    }

    /**
     * 如果不存在 premain(String agentOps, Instrumentation inst) 
     * 则会执行 premain(String agentOps)
     */
    public static void premain(String agentOps) {
        System.out.println("=========premain方法执行2========");
        System.out.println(agentOps);
    }

}
public class MyTransformer implements ClassFileTransformer {

    final static String prefix = "\nlong startTime = System.currentTimeMillis();\n";
    final static String postfix = "\nlong endTime = System.currentTimeMillis();\n";

    // 被处理的方法列表
    final static Map<String, List<String>> methodMap = new HashMap<String, List<String>>();

    public MyTransformer() {
        add("com.hwtest.demo.MyProgram.sayHello");
        add("com.hwtest.demo.MyProgram.sayHello2");
    }

    private void add(String methodString) {
        String className = methodString.substring(0, methodString.lastIndexOf("."));
        String methodName = methodString.substring(methodString.lastIndexOf(".") + 1);
        List<String> list = methodMap.get(className);
        if (list == null) {
            list = new ArrayList<String>();
            methodMap.put(className, list);
        }
        list.add(methodName);
    }

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
            ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        className = className.replace("/", ".");
        if (methodMap.containsKey(className)) {// 判断加载的class的包路径是不是需要监控的类
            CtClass ctclass = null;
            try {
                ctclass = ClassPool.getDefault().get(className);// 使用全称,用于取得字节码类<使用javassist>
                for (String methodName : methodMap.get(className)) {
                    String outputStr = "\nSystem.out.println(\"this method " + methodName
                            + " cost:\" +(endTime - startTime) +\"ms.\");";

                    CtMethod ctmethod = ctclass.getDeclaredMethod(methodName);// 得到这方法实例
                    String newMethodName = methodName + "$old";// 新定义一个方法叫做比如sayHello$old
                    ctmethod.setName(newMethodName);// 将原来的方法名字修改

                    // 创建新的方法,复制原来的方法,名字为原来的名字
                    CtMethod newMethod = CtNewMethod.copy(ctmethod, methodName, ctclass, null);

                    // 构建新的方法体
                    StringBuilder bodyStr = new StringBuilder();
                    bodyStr.append("{");
                    bodyStr.append(prefix);
                    bodyStr.append(newMethodName + "($$);\n");// 调用原有代码,类似于method();($$)表示所有的参数
                    bodyStr.append(postfix);
                    bodyStr.append(outputStr);
                    bodyStr.append("}");

                    newMethod.setBody(bodyStr.toString());// 替换新方法
                    ctclass.addMethod(newMethod);// 增加新方法
                }
                return ctclass.toBytecode();
            } catch (Exception e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        }
        return null;
    }
}

原始项目:

public class MyProgram {
    public static void main(String[] args) {
        sayHello();
        sayHello2("hello world222222222");
    }
    
    public static void sayHello() {
        try {
            Thread.sleep(2000);
            System.out.println("hello world!!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void sayHello2(String hello) {
        try {
            Thread.sleep(1000);
            System.out.println(hello);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

agent项目打jar包是配置为:

Manifest-Version: 1.0
Premain-Class: com.hwtest.MyAgent
Can-Redefine-Classes: true
Boot-Class-Path: javassist.jar

cmd执行命令

java -javaagent:MyAgent.jar  -jar MyProgram.jar


=========premain方法执行========
null
hello world!!
this method sayHello cost:2000ms.
hello world222222222
this method sayHello2 cost:1000ms.

 

 

 

 

地址记录:

(1)利用ClassFileTransformer实现aop:http://xj84.iteye.com/blog/1221105

(2)Java通过修改类的字节码实现aop功能:http://www.360doc.com/content/07/0518/11/25392_506401.shtml

(3)java.lang.instrument动态修改替换类代码:http://zctya.blog.163.com/blog/static/1209178201131944127774/

java Instrument修改字节码实现aop功能

标签:pen   tcl   rac   安全   dem   jar   cat   setname   declared   

原文地址:http://www.cnblogs.com/nnavvi/p/7340910.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!