zoukankan      html  css  js  c++  java
  • java agent 运行期织入【yetdone】

    https://www.cnblogs.com/silyvin/p/11260965.html,

    此前对javaagent的使用是在类加载期,需要重启应用才能织入,本次实践java agent运行期织入

    1. premain是静态修改,在类加载之前修改; attach是动态修改,在类加载后修改
    2. 要使premain生效重启应用,而attach不重启应用即可修改字节码并让其重新加载

    可以看到attach的方式更加强大,其核心原理首先是找到相关的进程id, 然后根据进程id去动态修改相关字节码

    还是参考这篇文章:https://www.jianshu.com/p/b2d09a78678d

    package agent;
    //
    //import com.sun.tools.attach.VirtualMachine;无法通过编译
    import javassist.ClassPool;
    import javassist.CtBehavior;
    import javassist.CtClass;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.lang.instrument.ClassFileTransformer;
    import java.lang.instrument.IllegalClassFormatException;
    import java.lang.instrument.Instrumentation;
    import java.lang.instrument.UnmodifiableClassException;
    import java.lang.reflect.Method;
    import java.security.ProtectionDomain;
    
    /**
     * https://www.cnblogs.com/silyvin/p/11260965.html
     * https://www.cnblogs.com/silyvin/p/11336727.html
     * Created by sunyuming on 19/7/28.
     */
    public class MyTransformer implements ClassFileTransformer {
    
        private ClassPool classPool = new ClassPool(true);
    
        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
    
            if(className.equals("agent/MyClient")) {
                System.out.println("类 " + className);
                try {
                    CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
                    for(CtBehavior ctBehavior : ctClass.getDeclaredBehaviors()) {
                        if(ctBehavior.getLongName().equals("agent.MyClient.print()")) {
                            System.out.println("开始处理方法 " + ctBehavior.getLongName());
                            ctBehavior.insertBefore("System.out.println("前置aop");");
                            ctBehavior.insertAfter("System.out.println("后置aop");");
                        }
                    }
                    return ctClass.toBytecode();
    
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            } else
                return null;
    
        }
    
        public static void agentmain(String agentArgs, Instrumentation inst)
                throws ClassNotFoundException, UnmodifiableClassException,
                InterruptedException {
            System.out.println("Agent Main start " + agentArgs);
            inst.addTransformer(new MyTransformer(), true);
            inst.retransformClasses(MyClient.class);
        }
    
        public static void premain(String args, Instrumentation instrumentation) {
            System.out.println("开始premain " + args);
            ClassFileTransformer classFileTransformer = new MyTransformer();
            instrumentation.addTransformer(classFileTransformer);
        }
    
        /**
         * premain
         * MANIFEST.MF.premain
         * cp target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar ~/Documents/tool/jars/myagentpre.jar
         * MANIFEST.MF
         * java -javaagent:/Users/sunyuming/Documents/tool/jars/myagentpre.jar=sun -jar target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar
         */
    
        /**
         * agentmain
         * MANIFEST.MF
         * cp target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar ~/Documents/tool/jars/myagented.jar
         * java -jar ~/Documents/tool/jars/myagented.jar
         * 另一个terminal
         * MANIFEST.MF.agentmain
         * jps
         * java -Djava.ext.dirs=${JAVA_HOME}/lib -jar target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar 47929
         */
    
        public static void main(String [] args) throws Exception {
            final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Class vmClass = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
            Object vm = vmClass.getMethod("attach", String.class).invoke(null, args[0]);
            String path = MyTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath();
            // main与agentmain也可以分开,体现在path上,我们这边合并
            vmClass.getMethod("loadAgent", String.class, String.class).invoke(vm, path, "");
    
    // 无法通过编译,除非在pom中加入tool,即使如此,运行期也需要 -Djava.ext.dirs=${JAVA_HOME}/lib
    //        VirtualMachine vm = VirtualMachine.attach(args[0]); //正在运行的java 程序 ps id
    //        vm.loadAgent("/Users/sunyuming/work/MyTest/target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar");
    
        }
    }
    

    被注入的jar

    Manifest-Version: 1.0
    Main-Class: agent.MyClient

    agent

    Manifest-Version: 1.0
    Main-Class: agent.MyTransformer
    Agent-Class: agent.MyTransformer
    Can-Redefine-Classes: true
    Can-Retransform-Classes: true

    premain

    Manifest-Version: 1.0
    Premain-Class: agent.MyTransformer

    2个附属:

    1)也许以后补充一个asm

    2)配置文件是否可以?

  • 相关阅读:
    注解的作用
    962. Maximum Width Ramp
    594. Longest Harmonious Subsequence
    1042. Flower Planting With No Adjacent
    419. Battleships in a Board
    1041. Robot Bounded In Circle
    leetcode 395. Longest Substring with At Least K Repeating Characters(高质量题)
    leetcode 44. Wildcard Matching(模糊匹配)
    HEU预热赛
    780. Reaching Points
  • 原文地址:https://www.cnblogs.com/silyvin/p/11336727.html
Copyright © 2011-2022 走看看