java反射之Call stack introspection

原创 2016年08月30日 22:51:32

java反射之Call stack introspection

java是基于栈设计的语言,其实与C、C++语言相同。整个程序的运行表现在方法的执行是一系列入栈出栈的行为,栈是线程私有的。

在java语言中,我们可以跟踪方法的调用关系,即当前栈帧(栈顶)和已经入栈的栈帧的层次关系。

从java1.4以后,java语言的Throwable类提供了以下方法:


Open Declaration StackTraceElement[] java.lang.Throwable.getStackTrace()


Provides programmatic access to the stack trace information printed by printStackTrace(). Returns an array of stack trace elements, each representing one stack frame. The zeroth element of the array (assuming the array's length is non-zero) represents the top of the stack, which is the last method invocation in the sequence. Typically, this is the point at which this throwable was created and thrown. The last element of the array (assuming the array's length is non-zero) represents the bottom of the stack, which is the first method invocation in the sequence. 

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 throwable is permitted to return a zero-length array from this method. Generally speaking, the array returned by this method will contain one element for every frame that would be printed by printStackTrace. Writes to the returned array do not affect future calls to this method.

Returns:
an array of stack trace elements representing the stack trace pertaining to this throwable.
Since:
1.4


该方法返回的StackTraceElement[] 就是栈帧数组。数组下标0的元素代表当前栈顶栈帧,数组的最大下标代表调用栈序列中第一个栈帧,也就是第一个方法的调用。我们可以从StackTraceElement得到栈调用层级的关系、调用方法名及调用入口位置,代码示例:




执行结果:



调用结果显示的方法调用层级关系。
 那我们得到这些信息有什么用呢。
1.日志:这些信息可以让应用的日志系统得到信息更详细。
2.安全:API可以决定调用者当前包或者类是否有权限进入。
3.流程控制:可以避免一些流程错误,比如无限递归调用。

实现一个简单的日志系统:

package com.doctor.reflect;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * Call stack introspection
 * 
 * @author sdcuike
 *
 *         Created At 2016年8月29日 下午9:40:35
 */
public class CallStackIntrospectionDemo {
    private static final MyLogger logger = new LoggerImpl();

    public static void main(String[] args) {
        logger.logRecord("hello");

        IllegalArgumentException exception = new IllegalArgumentException("IllegalArgumentException");
        logger.logProblem("throwable", exception);
    }

    public interface MyLogger {
        // Types for log records
        int ERROR   = 0;
        int WARNING = 100;
        int STATUS  = 200;
        int DEBUG   = 300;
        int TRACE   = 400;

        void logRecord(String message);

        void logProblem(String message, Throwable throwable);
    }

    public static class LoggerImpl implements MyLogger {

        @Override
        public void logRecord(String message) {
            Throwable throwable = new Throwable();
            log(message, throwable.getStackTrace()[1]);
        }

        @Override
        public void logProblem(String message, Throwable throwable) {
            StringWriter out = new StringWriter();
            PrintWriter writer = new PrintWriter(out);
            throwable.printStackTrace(writer);
            writer.flush();
            log(message + out.toString(), throwable.getStackTrace()[0]);
        }

        private void log(String message, StackTraceElement stackTraceElement) {
            String className = stackTraceElement.getClassName();
            String methodName = stackTraceElement.getMethodName();
            int lineNumber = stackTraceElement.getLineNumber();
            System.out.println(String.join("  ", "模拟打印日志:", methodName, className, "" + lineNumber, message));
        }

    }
}

执行结果:

模拟打印日志:  main  com.doctor.reflect.CallStackIntrospectionDemo  36  hello
模拟打印日志:  main  com.doctor.reflect.CallStackIntrospectionDemo  38  throwablejava.lang.IllegalArgumentException: IllegalArgumentException
	at com.doctor.reflect.CallStackIntrospectionDemo.main(CallStackIntrospectionDemo.java:38)

上述日志,只是简单的在控制台打印一些信息。


参考:java doc
 Java Reflection in Action   第五章 Call stack introspection


版权声明:本文为博主原创文章,未经博主允许不得转载[http://blog.csdn.net/doctor_who2004]。

相关文章推荐

Java JDK Introspection

内省(IntroSpector)是Java 语言对 Bean 类属性、事件的一种缺省处理方法。例如类 A 中有属性 name, 那我们可以通过 getName,setName 来得到其值或者设置新的值...

Collecting the call stack in real time

  • 2008年10月04日 15:11
  • 27KB
  • 下载

trace call stack demo

  • 2008年08月05日 16:42
  • 3KB
  • 下载

XUL扩展:在javascript脚本中查看call stack

通常我们使用venkman扩展来调试javascript脚本,绝大部分情况下都很效,尤其是单步跟踪和查看call stack。但venkman也有不灵光的时候,比如有时人品不好,发现在source c...

调用栈 (Call Stack)

调用栈的英文叫做call stack,从其英文书名来看,知道它本身就是一个栈,故而它满足栈的先入后出的特性。 wiki上有篇文章讲述call stack。 关于栈的溢出(stack...

call_function_single_interrupt stack checking

The symbol call_function_single_interrupt is defined in entry_64.S, and it's an assembly routine. It...
  • cl55
  • cl55
  • 2015年11月13日 22:06
  • 587

JS 异常: Uncaught RangeError: Maximum call stack size exceeded

JS 异常: Uncaught RangeError: Maximum call stack size exceeded

Windbg调试--Get the Call Stack back when met UnhandledExceptionFilter

一、.符号文件的设定: File->Symbol Path 中填写: srv*f:\Symbols*http://msdl.microsoft.com/download/symbols;\\10....
  • bosbear
  • bosbear
  • 2012年02月22日 21:37
  • 1781

屏幕分辨率改变导致Maximum call stack size exceeded

今天遇到一个超级奇怪的问题,屏幕分辨率调低之后,js报错Maximum call stack size exceeded。 溢出的这个错误为什么和屏幕分辨率有关呢,极有可能是和js里对高度,宽度等值的...

mongoose报错:RangeError: Maximum call stack size exceeded

mongoose报错:RangeError: Maximum call stack size exceeded
  • farYang
  • farYang
  • 2016年05月26日 10:36
  • 784
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java反射之Call stack introspection
举报原因:
原因补充:

(最多只允许输入30个字)