出于调试目的,我需要在类中执行某些代码。我想用XML生成所有方法调用的日志,如:
<call class='pack.age.MyClass' method='myMethod1'>
<param name='param1'>param1.toString() value</param>
...
<call>Call to other method within myMethod1; you get the idea</call>
</call>
因为这个类是长并且很多的方法,我想知道是否有办法一般地访问参数,可能使用反射。我在方法内部,我想循环给这个方法调用的参数。它可以减轻我的痛苦,让我做一个正则表达式来添加日志行。有可能吗?
任何其他简洁的方式来表达赞赏(但AOP不是一个真正的选择)。
答案 0 :(得分:2)
在每个方法的开头添加对log()
的调用。在log()
内,要么抛出异常(对于Java 1.4),要么使用Thread.currentThread().getStackTrace()
来获取堆栈跟踪。
这将为您提供StackTraceElement
的数组。您要查找的元素位于索引1(这是调用log()
的位置)。使用getMethodName()
获取方法的名称。之后,您可以使用反射来检查方法。
不幸的是,这不会让您访问真正的Java堆栈,因此您无法打印参数的值。一种解决方案是简单地将它们复制到日志调用中,并使用方法上的反射来确定它们是什么。使用Java 5,可变参数列表(log(Object...args)
)是您的朋友。
另一个选项是使用Java Debugger API并编写一个小调试器。在这种情况下,RemoteStackFrame
将包含参数和值。
如果这工作太多,只需使用十行AOP即可完成。
答案 1 :(得分:2)
另一种方法是使用像BTrace这样的动态跟踪器(类似于AOP,但在代码之外)。请查看http://kenai.com/projects/btrace/pages/UserGuide示例。甚至还有VisualVM插件可以附加到正在运行的进程,这使得thigs更容易。使用以下BTrace代码,您将获得方法调用及其参数(摘自示例)。
import com.sun.btrace.AnyType;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace public class YourCalls {
@OnMethod(clazz="pack.age.MyClass", method="myMethod1",
location=@Location(value=Kind.CALL, clazz="/.*/", method="/.*/"))
public static void o(AnyType[] args) { // all calls to methods
printArray(args);
}
}
将BTrace附加到正在运行的程序很容易。在此调用之后,首先使用jps获取进程的PID:
btrace PID YourCalls.java
答案 2 :(得分:1)
奇怪建议:
类似的东西:
class A
{
public void sayHello()
{
System.err.println("OK");
}
}
class B
extends A
{
private A delegate;
public B(A delegate) { this.delegate=delegate);}
@Override
public void sayHello()
{
beginMyMethod();
delegate.sayHello();
endMyMethod();
}
}