美文网首页
ASM(动态增强)

ASM(动态增强)

作者: 火火说技术 | 来源:发表于2018-05-08 13:25 被阅读0次

    ASM(动态)

    前面那篇是静态修改字节码的方式,这种方式只是一种demo,方便初学者进行学习基本的API操作,真正在线上环境有作用的是动态的去修改字节码。

    例如一个进程正在运行着,这个时候我们需要在业务无感知的情况下进行打印日志,或者计算接口的操作时间这种操作,这个时候我们就需要动态的去操作JVM中的字节码文件了

    动态操作字节码

    动态操作字节码的方式,其实还是主要使用agentmain,在javaagent的类attch到jvm上面的时候会调用这个方法执行内部的代码逻辑。

    如何使用

    首先我们需要有一个agent,这个agent实现了agentmain的方法,并且改写对应类的字节码文件。DynamicPreMainAddTimeStatAgent

    public class DynamicPreMainAddTimeStatAgent {
    
    
        public static void agentmain(String agentArgs, Instrumentation inst) throws Exception {
            System.out.println("Agent Main called");
            System.out.println("agentArgs:" + agentArgs);
            inst.addTransformer(new ClassFileTransformer() {
                public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
                    System.out.println("load transform");
    
                    if (className.equals("com/wsqandgy/asm/dynamic/Account")) {
                        System.out.println("meet com/wsqandgy/asm/dynamic/Account ");
                        /** classfileBuffer */
                        ClassReader classReader = new ClassReader(classfileBuffer);
                        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
                        TimeStatClassAdapter timeStatClassAdapter = new TimeStatClassAdapter(cw);
                        classReader.accept(timeStatClassAdapter, ClassReader.SKIP_DEBUG);
                        byte[] data = cw.toByteArray();
                        return data;
                    } else {
                        System.out.println("load class:" + className);
                        System.out.println("new !");
                        return classfileBuffer;
                    }
                }
            },true);
            System.out.println(Account.class.getClassLoader());
            inst.retransformClasses(Account.class);
        }
    }
    

    在上述操作中使用了TimeStatClassAdapter这个Class修改适配器和TimeStatMethodAdapter修改适配器。

    增加TimeStat的方法,提供打印运行时间的方法。

    public class TimeStat {
        static ThreadLocal<Long> t = new ThreadLocal<Long>();
    
    
        public static void start() {
            t.set(System.currentTimeMillis());
        }
    
        public static void end() {
            long time = System.currentTimeMillis();
            System.out.print(Thread.currentThread().getStackTrace()[2] + " spend:");
            System.out.println(time - t.get());
        }
    }
    

    针对上面的内容创建MANIFEST.MF文件,并且进行打成jar包。

    Manifest-Version: 1.0
    Agent-Class: com.wsqandgy.asm.dynamic.DynamicPreMainAddTimeStatAgent
    Can-Redefine-Classes: true
    Can-Retransform-Classes: true
    
    

    以上就是全部改写字节码文件的类和agentmain对应方法的类文件了。众所周知,我们需要对JVM进行注入就需要获取到全部的JVM运行信息,Java提供了一个方法可以获取到运行的JVM的相关信息。List<VirtualMachineDescriptor> list = VirtualMachine.list();

    我们通过以上的方法获取到对应的JVM运行实例,进行attch操作。

    public class AttachToolMain {
        public static void main(String[] args) throws Exception {
            List<VirtualMachineDescriptor> list = VirtualMachine.list();
            for (VirtualMachineDescriptor machineDescriptor : list) {
                if (machineDescriptor.displayName().equals("com.wsqandgy.asm.dynamic.RunLoopAccountMain")) {
                    VirtualMachine virtualMachine = VirtualMachine.attach(machineDescriptor.id());
                    System.out.println(new File("/Users/gongyan/Documents/home_code/tools/classes/artifacts/dynamicTimeAgent/dynamicTimeAgent.jar").exists());
                    virtualMachine.loadAgent("/Users/gongyan/Documents/home_code/tools/classes/artifacts/dynamicTimeAgent/dynamicTimeAgent.jar","argument for agent");
                    System.out.println("attach ok!");
                    virtualMachine.detach(); // 派遣操作,意思为生效
                }
            }
        }
    }
    

    运行效果:

    before

    当我们运行AttachToolMain后,字节码重新生成已经增加了对应的响应时间了。

    after

    相关文章

      网友评论

          本文标题:ASM(动态增强)

          本文链接:https://www.haomeiwen.com/subject/hfnirftx.html