如何在Java中跟踪方法结果

时间:2017-11-09 16:56:00

标签: java reflection proxy-pattern

简而言之,我正在开发一个能够为您提供有关执行java程序所提供结果的信息的系统。我考虑过以下问题,我不知道是否可以在java中解决它。

我有以下课程:

public class ClassA {
    ClassB classB= new ClassB();
    public Integer method1(){
       return classB.method2();
    }
}

public class ClassB {
    ClassC classC = new ClassC();
    public Integer method2() {
        return this.classC.method3() + this.classC.method4();
    }
}

public class ClassC {
    public Integer method3() {
        return 3;
    }
    public Integer method4() {
        return 4;
    }
}

到目前为止,我可以使用动态代理捕获方法的每次调用。特别是,我正在使用java.lang.reflect包中的Proxy和InvocationHandler对象。这里有我遵循的例子(https://www.concretepage.com/java/dynamic-proxy-with-proxy-and-invocationhandler-in-java)。

我的问题是,如果有人知道如何提供以下信息: "方法1()的返回是从method2()的返回生成的,而method2()的返回又是从method3()的返回和method4()"的返回生成的。

3 个答案:

答案 0 :(得分:0)

您需要使用ThreadLocals。线程本地将有一个Map将由每个方法填充。以下是示例代码:

((z > 7) and ((x = 5) or (y > 6)))

答案 1 :(得分:0)

我之前使用过仪器来解决类似的问题。

  

免责声明:如果您可以控制JVM,则只能执行以下操作,并且可以将其指定为与javaagent一起运行。

代理实现起来相当简单,您只需要一个实现premain(String, java.lang.Instrumentation)签名方法的类。一个例子如下:

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.lang.instrumentation.ClassFileTransformer;
import java.lang.instrumentation.IllegalClassFormatException;
import java.lang.instrumentation.Instrumentation;
import java.security.ProtectionDomain;

public class MyAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        inst.addTransformer(new ClassTransformer() {
            public byte[] transform(ClassLoader loader, String className,
                    Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
                    byte[] classfileBuffer) throws IllegalClassFormatException {
            // if you want to target specific classes or packages you can filter
            // on the class name, just remember that it is the JVM class format string
            if(className.startWith("com/my/package/SomeThing")) {
                // javassist provides methods to access classes and generate bytecode
                ClassPool cp = ClassPool.getDefault();
                // you can access the class with the following
                CtClass cc = cp.get("com.my.package.MyClass$InnerClass");
                // access specific methods with
                CtMethod m = cc.getDeclaredMethod("someMethod");
                m.setBody("{MyCallTree tree = com.my.package.TreeSingleton.getTree();\ntree.addCall(" + m.getLongName + ");\n}");
                return cc.toByteCode();
            }
            else {
                // return null so that you don't break methods or classes you
                // don't want to
                return null;
            }
        });
    }
}

在上面的代码段中,我替换了整个方法正文,代码作为字符串传递给CtMethod.setBody。但是,您几乎可以使用javassist,前置代码,附加代码等进行任何操作。可以找到有关使用javassist的详细教程here。它是一个非常强大的库。

如何实现代码来构建调用信息的细节实际上只是Java代码,可能先将代码作为项目的一部分编写,然后只使用在premain中执行步法的位方法。你甚至可以让它在答案中写出tsolakp建议的代码。

下一步是将上述代码打包到jar文件中,然后在启动时将其注入JVM,如this answer中所述。

答案 2 :(得分:-1)

我想到的一件事是检索一个线程的堆栈跟踪,看看你能做些什么。

你可以用例如。 Thread.currentThread().getStackTrace()方法并接收StackTraceElement数组,最后使用它们来接收带有getMethodName()方法的方法名称。

这只是一个想法,我不确定你是否能得到你想要的信息。