Java反射之Call stack introspection详解
程序员文章站
2024-04-01 20:48:46
java是基于栈设计的语言,其实与c、c++语言相同。整个程序的运行表现在方法的执行是一系列入栈出栈的行为,栈是线程私有的。
在java语言中,我们可以跟踪方法的调用关系...
java是基于栈设计的语言,其实与c、c++语言相同。整个程序的运行表现在方法的执行是一系列入栈出栈的行为,栈是线程私有的。
在java语言中,我们可以跟踪方法的调用关系,即当前栈帧(栈顶)和已经入栈的栈帧的层次关系。
从java1.4以后,java语言的throwable类提供了以下方法:
opendeclarationstacktraceelement[]java.lang.throwable.getstacktrace() providesprogrammaticaccesstothestacktraceinformationprintedbyprintstacktrace().returnsanarrayofstacktraceelements,eachrepresentingonestackframe.thezerothelementofthearray(assumingthearray'slengthisnon-zero)representsthetopofthestack,whichisthelastmethodinvocationinthesequence.typically,thisisthepointatwhichthisthrowablewascreatedandthrown.thelastelementofthearray(assumingthearray'slengthisnon-zero)representsthebottomofthestack,whichisthefirstmethodinvocationinthesequence. somevirtualmachinesmay,undersomecircumstances,omitoneormorestackframesfromthestacktrace.intheextremecase,avirtualmachinethathasnostacktraceinformationconcerningthisthrowableispermittedtoreturnazero-lengtharrayfromthismethod.generallyspeaking,thearrayreturnedbythismethodwillcontainoneelementforeveryframethatwouldbeprintedbyprintstacktrace.writestothereturnedarraydonotaffectfuturecallstothismethod. returns: anarrayofstacktraceelementsrepresentingthestacktracepertainingtothisthrowable. 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反射之call stack introspection详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:
如有不足之处,欢迎留言指出。