比如有2个类:ClassA,ClassB
ClassA的一个实例调用了ClassB的一个方法,通过动态代理可以截取这个调用,但是不能获得是谁调用了ClassB的方法,如何才能截取到呢,
下面给个思路.
java代码:
public static String getCaller(){ |
t, to be in the format
java.lang.Throwable
...
at org.apache.log4j.PatternLayout.format(PatternLayout.java:413)
at org.apache.log4j.FileAppender.doAppend(FileAppender.java:183)
at org.apache.log4j.Category.callAppenders(Category.java:131)
at org.apache.log4j.Category.log(Category.java:512)
at callers.fully.qualified.className.methodName(FileName.java:74)
...
t, to be in the format
java.lang.Throwable
...
at org.apache.log4j.PatternLayout.format(PatternLayout.java:413)
at org.apache.log4j.FileAppender.doAppend(FileAppender.java:183)
at org.apache.log4j.Category.callAppenders(Category.java:131)
at org.apache.log4j.Category.log(Category.java:512)
at callers.fully.qualified.className.methodName(FileName.java:74)
...
However, we can also deal with JIT compilers that "lose" the
location information, especially between the parentheses.
*/
public LocationInfo(Throwable t, String fqnOfInvokingClass) {
if(PlatformInfo.hasStackTraceElement()) {
StackTraceElementExtractor.extract(this, t, fqnOfInvokingClass);
} else {
LegacyExtractor.extract(this, t, fqnOfInvokingClass);
}
}
可以看到,Log4J首先判断Java平台是否支持StackTraceElement,如果是,那么用StackTraceElementExtractor,否则使用原来的LegacyExtractor。
下面来看StackTraceElementExtractor.java
/**
* A faster extractor based on StackTraceElements introduced in JDK 1.4.
*
* The present code uses reflection. Thus, it should compile on all platforms.
*
* @author Martin Schulz
* @author Ceki G&lc&
*
*/
public class StackTraceElementExtractor {
protected static boolean haveStackTraceElement = false;
private static Method getStackTrace = null;
private static Method getClassName = null;
private static Method getFileName = null;
private static Method getMethodName = null;
private static Method getLineNumber = null;
…. // 以下代码省略
可以看到,Log4J 1.3仍然兼容JDK1.3,而且为JDK1.4也做了相应的优化。
五、JDK1.5的Thread Stack Trace
JDK1.5在Thread类里面引入了getStackTrace()和getAllStackTraces()两个方法。这下子,我们不用 (new Throwable()).getStackTrace ();可以调用
Thread.getCurrentThread().getStackTrace()来获得当前线程的运行栈信息。不仅如此,只要权限允许,还可以获得其它线程的运行栈信息。
/**
* Returns an array of stack trace elements representing the stack dump
* of this thread. This method will return a zero-length array if
* this thread has not started or has terminated.
* If the returned array is of non-zero length then the first element of
* the array represents the top of the stack, which is the most recent
* method invocation in the sequence. The last element of the array
* represents the bottom of the stack, which is the least recent method
* invocation in the sequence.
*
*
If there is a security manager, and this thread is not
* the current thread, then the security manager's
* checkPermission method is called with a
* RuntimePermission("getStackTrace") permission
* to see if it's ok to get the stack trace.
*
*
Some virtual machines may, under some circumstances, omit one
* or more stack frames from the stack trace. In the extreme case,
* a virtual machine that has no stack trace information concerning
* this thread is permitted to return a zero-length array from this
* method.
*
* @return an array of StackTraceElement,
* each represents one stack frame.
*
* @since 1.5
*/
public StackTraceElement[] getStackTrace() {
if (this != Thread.currentThread()) {
// check for getStackTrace permission
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
SecurityConstants.GET_STACK_TRACE_PERMISSION);
}
}
if (!isAlive()) {
return EMPTY_STACK_TRACE;
}
Thread[] threads = new Thread[1];
threads[0] = this;
StackTraceElement[][] result = dumpThreads(threads);
return result[0];
}
/**
* Returns a map of stack traces for all live threads.
*
* @since 1.5
*/
public static Map
// check for getStackTrace permission
// Get a snapshot of the list of all threads
}
六、总结
从总的发展趋势来看,JDK不仅提供越来越多、越来越强的功能,而且暴露给用户的控制方法越来越多,越来越强大。
关于直接获取调用类名的方法。
我们来看sun.reflect.Reflection的getCallerClass()方法的说明。
java代码:
/** Returns the class of the method realFramesToSkip
frames up the stack (zero-based), ignoring frames associated
with java.lang.reflect.Method.invoke() and its implementation.
The first frame is that associated with this method, so getCallerClass(0) returns the Class object for
sun.reflect.Reflection. Frames associated with
java.lang.reflect.Method.invoke() and its implementation are
completely ignored and do not count toward the number of "real"
frames skipped. */
public static native Class getCallerClass(int realFramesToSkip);
这是一个native方法。原理也是根据StackFrame(运行栈)获取相应类的信息。这个方法直接返回一个Class名字,直接有效。参数realFramesToSkip用来选取你所需要的Stack层次,所以,你可以用这个方法获得任何层次的上的调用类名。
你可以使用这个链接引用该篇文章 http://publishblog.blogchina.com/blog/tb.b?diaryID=1904804
|
- 评论人:sunshineblue
2006-03-03 22:24:09
|
|||
感觉写得很好
|
||||