【问题标题】:Look at the source code of a Java class modified by a Java Agent看一个Java Agent修改的Java类的源码
【发布时间】:2018-05-23 11:46:31
【问题描述】:

我需要查看 Java 代理如何修改我的初始类,以便了解代码的作用。

build.gradle

configurations {
    jar.archiveName = 'agent2.jar'
}

jar {
    manifest {
        attributes(
                "Premain-Class": "com.training.agentexample.Agent",
                "Can-Redefine-Classes": false,
                "Can-Set-Native-Method-Prefix": false
        )
    }

    //Fat jar with all dependencies.
    from {
        (configurations.runtime).collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
}

dependencies {
    compile group: 'org.javassist', name: 'javassist', version: '3.22.0-GA'
}

Main.java

public class Main {

    public static void main(String[] args) {
        System.currentTimeMillis();
        App app = new App();
        app.execute("John");
        Scanner in = new Scanner(System.in);
        System.out.println("Enter text to exit");
        in.next();   //Wait until the user clicks to proceed.
    }
}

App.java

public class App {

    public void execute(String param) {
        String message = "Hello World";
        System.out.println(message + " " + param);
    }
}

Agent.java

public class Agent {

    public static void premain(final String agentArgs, final Instrumentation inst) {
        System.out.println("Hey, look: I'm instrumenting a freshly started JVM!");
        inst.addTransformer(new RuntimeTimerTransformer());
    }
}

RuntimeTimerTransformer.java

public class RuntimeTimerTransformer implements ClassFileTransformer {

    public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) {
        return transformClass(redefiningClass, bytes);
    }

    private byte[] transformClass(Class classToTransform, byte[] b) {
        ClassPool pool = ClassPool.getDefault();
        CtClass cl = null;
        try {
            cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
            CtBehavior[] methods = cl.getDeclaredBehaviors();
            for (CtBehavior method : methods) {
                if (!method.isEmpty()) {
                    changeMethod(method);
                }
            }
            b = cl.toBytecode();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cl != null) {
                cl.detach();
            }
        }
        return b;
    }

    private void changeMethod(CtBehavior method) throws CannotCompileException {
        String name = method.getName();
        if (name.equals("execute")) {
            addElapsedTime(method);
        }
    }

    private void addElapsedTime(CtBehavior method) throws CannotCompileException {
        method.addLocalVariable("$_start", CtClass.longType);
        method.addLocalVariable("$_end", CtClass.longType);
        method.addLocalVariable("$_total", CtClass.longType);
        method.insertBefore("{ $_start = System.nanoTime();\nSystem.out.println($0);\n$1 = \"Robert\"; }");
        method.insertAfter("{ $_end = System.nanoTime();\n$_total = $_end - $_start;\nSystem.out.println($_total);\nthrow new RuntimeException(\"Break!\"); }");
    }
}

我从 Intellij Idea 调试它。我设置JAVA_TOOL_OPTIONS=-javaagent:"C:\Development\agent-example\build-gradle\libs\agent2.jar"=name=agentExample

Output

Hey, look: I'm instrumenting a freshly started JVM!
Connected to the target VM, address: '127.0.0.1:64486', transport: 'socket'
Exception in thread "main" java.lang.RuntimeException: Break!
    at app.App.execute(App.java:10)
    at app.app.Main.main(Main.java:12)
app.app.App@3e6fa38a
Hello World !Robert
736583
Picked up JAVA_TOOL_OPTIONS: -javaagent:"C:\Development\agent-example\java-assist-agent\build\libs\agent2.jar"=name=agentExample
Disconnected from the target VM, address: '127.0.0.1:64486', transport: 'socket'

Process finished with exit code 1

我可以设置断点。我的问题。 我如何查看正在执行的真实源代码?顺便说一句,您可以使用此代码作为示例来开始使用 Java 代理。

【问题讨论】:

    标签: java javaagents


    【解决方案1】:

    这不是我想要的答案,但这是我能得到的答案。 我仍然需要一个更好的解决方案,尤其是如果我无法访问代理代码怎么办。欢迎您的想法!

    1) 修改transform方法。

    private byte[] transformClass(Class classToTransform, byte[] b) {
        ClassPool pool = ClassPool.getDefault();
        CtClass cl = null;
        try {
            cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
            CtBehavior[] methods = cl.getDeclaredBehaviors();
            for (CtBehavior method : methods) {
                if (!method.isEmpty()) {
                    changeMethod(method);
                }
            }
            b = cl.toBytecode();
    
            OutputStream os = new FileOutputStream(CLASS_OUTPUT_DIR + cl.getName() + CLASS_EXTENSION);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            bos.write(b);
            bos.close();
    
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cl != null) {
                cl.detach();
            }
        }
        return b;
    }
    

    更新

    见下文更新。我使用 Intellij Idea 打开字节码类。

    2) 然后打开字节码。我使用了 jd-gui-1.4.0.jar。这就是我得到的。

    编译App.class

    public class App
    {
      /* Error */
      public void execute(String param)
      {
        // Byte code:
        //   0: invokestatic 55 java/lang/System:nanoTime   ()J
        //   3: lstore 4
        //   5: getstatic 4 java/lang/System:out    Ljava/io/PrintStream;
        //   8: aload_0
        //   9: invokevirtual 58    java/io/PrintStream:println (Ljava/lang/Object;)V
        //   12: ldc 60
        //   14: astore_1
        //   15: ldc 2
        //   17: astore_2
        //   18: ldc 3
        //   20: astore_3
        //   21: getstatic 4    java/lang/System:out    Ljava/io/PrintStream;
        //   24: aload_2
        //   25: invokevirtual 5    java/io/PrintStream:println (Ljava/lang/String;)V
        //   28: getstatic 4    java/lang/System:out    Ljava/io/PrintStream;
        //   31: new 6  java/lang/StringBuilder
        //   34: dup
        //   35: invokespecial 7    java/lang/StringBuilder:<init>  ()V
        //   38: aload_2
        //   39: invokevirtual 8    java/lang/StringBuilder:append  (Ljava/lang/String;)Ljava/lang/StringBuilder;
        //   42: aload_3
        //   43: invokevirtual 8    java/lang/StringBuilder:append  (Ljava/lang/String;)Ljava/lang/StringBuilder;
        //   46: aload_1
        //   47: invokevirtual 8    java/lang/StringBuilder:append  (Ljava/lang/String;)Ljava/lang/StringBuilder;
        //   50: invokevirtual 9    java/lang/StringBuilder:toString    ()Ljava/lang/String;
        //   53: invokevirtual 5    java/io/PrintStream:println (Ljava/lang/String;)V
        //   56: goto +3 -> 59
        //   59: aconst_null
        //   60: astore 11
        //   62: invokestatic 55    java/lang/System:nanoTime   ()J
        //   65: lstore 6
        //   67: lload 6
        //   69: lload 4
        //   71: lsub
        //   72: lstore 8
        //   74: getstatic 4    java/lang/System:out    Ljava/io/PrintStream;
        //   77: lload 8
        //   79: invokevirtual 63   java/io/PrintStream:println (J)V
        //   82: new 65 java/lang/RuntimeException
        //   85: dup
        //   86: ldc 67
        //   88: invokespecial 69   java/lang/RuntimeException:<init>   (Ljava/lang/String;)V
        //   91: athrow
        //   92: athrow
        // Line number table:
        //   Java source line #6    -> byte code offset #15
        //   Java source line #7    -> byte code offset #18
        //   Java source line #8    -> byte code offset #21
        //   Java source line #9    -> byte code offset #28
        //   Java source line #10   -> byte code offset #56
        // Local variable table:
        //   start  length  slot    name    signature
        //   0  59  0   this    App
        //   0  59  1   param   String
        //   18 41  2   message String
        //   21 38  3   appender    String
        //   0  59  4   $_start long
        //   0  59  6   $_end   long
        //   0  59  8   $_total long
      }
    }
    

    在理念中

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-29
      • 2016-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多