简而言之,我正在开发一个能够为您提供有关执行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()"的返回生成的。
答案 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()
方法的方法名称。
这只是一个想法,我不确定你是否能得到你想要的信息。