得到当前堆栈信息的两种方式(Thread和Throwable)的纠结
今天进行slf4j中logger的同步封装。主要目的是为了以后方便更换日志实现系统。
遇到的问题:使用Thread.currentThread().getStackTrace()[1].getClassName()得到的是当前类而不是调用类。见以下代码:
private org.slf4j.Logger logger = null; /**
* construction method
*/
public Logger(){
// get the current class logger
logger = LoggerFactory.getLogger(Thread.currentThread().getStackTrace()[1].getClassName());
}
所以打印日志的时候并没有得到日志真正所属类的信息。
然后,我进行了一组測试:
測试A:
public class ThreadTest {
public static void TestString(){
StackTraceElement[] arr = new Exception().getStackTrace();
for(int i=0;i<=arr.length-1;i++){
System.out.println(arr[i].getClassName()+";"+arr[i].getMethodName()+";"+arr[i].getFileName());
}
}
}
public class App
{
public static void main( String[] args )
{
ThreadTest.TestString();
}
}
结果是:
test.ThreadTest;TestString;ThreadTest.java(当前方法和类)
test.App;main;App.java(调用该方法的方法和类)
測试B:
public class ThreadTest {
public static void TestString(){
StackTraceElement[] arr = Thread.currentThread().getStackTrace();
for(int i=0;i<=arr.length-1;i++){
System.out.println(arr[i].getClassName()+";"+arr[i].getMethodName()+";"+arr[i].getFileName());
}
}
}
App类同上。得到的结果是:
java.lang.Thread;getStackTrace;Thread.java(Thread的信息)
test.ThreadTest;TestString;ThreadTest.java(当前方法和类)
test.App;main;App.java(调用该方法的方法和类)
啥米情况???难道就是由于Thread的getStackTrace比Throwable(Exception的父类)的getStackTrace多打了一段Thread类的信息???
因为不确定是不是真的是这样子的,故去查看了下jdk的源代码(纯属装X,不抱幻想)。
首先是Throwable的getStackTrace方法,代码例如以下:
public StackTraceElement[] getStackTrace() {
return getOurStackTrace().clone();
}
private synchronized StackTraceElement[] getOurStackTrace() {
// Initialize stack trace field with information from
// backtrace if this is the first call to this method
if (stackTrace == UNASSIGNED_STACK ||
(stackTrace == null && backtrace != null) /* Out of protocol state */) {
int depth = getStackTraceDepth();
stackTrace = new StackTraceElement[depth];
for (int i=0; i < depth; i++)
stackTrace[i] = getStackTraceElement(i);
} else if (stackTrace == null) {
return UNASSIGNED_STACK;
}
return stackTrace;
}
貌似没有什么不正确劲的地方哈,当中
int depth = getStackTraceDepth();
stackTrace[i] = getStackTraceElement(i);
两个方法都是native的,不予深究了。这里没有找到问题。就去看了下Thread的getStackTrace方法,代码例如以下:
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);
}
// optimization so we do not call into the vm for threads that
// have not yet started or have terminated
if (!isAlive()) {
return EMPTY_STACK_TRACE;
}
StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});
StackTraceElement[] stackTrace = stackTraceArray[0];
// a thread that was alive during the previous isAlive call may have
// since terminated, therefore not having a stacktrace.
if (stackTrace == null) {
stackTrace = EMPTY_STACK_TRACE;
}
return stackTrace;
} else {
// Don't need JVM help for current thread
return (new Exception()).getStackTrace();
}
}
乍一看也没啥错啊~~~不正确,突然间跟着逻辑走一下。在if语句里面由于
this != Thread.currentThread()是为true的。所以方法会运行else里面的语句,里面是啥。!!
!
return (new Exception()).getStackTrace();
All right!
就是这里,这里jvm去运行了new Exception().getStackTrace();就是这句话让使用Thread的getStackTrace方法就有可能多打印一句java.lang.Thread;getStackTrace;Thread.java出来。这也就是为什么使用
logger = LoggerFactory.getLogger(Thread.currentThread().getStackTrace()[1].getClassName());
会得不到正确的日志信息的原因了。
应该就是这样子了。为了验证我想的对不正确,写了一个測试验证的样例,代码例如以下:
public class TestException {
public static StackTraceElement[] getStackTrace() {
return new Exception().getStackTrace();
}
}
public class ThreadTest {
public static void TestString(){
StackTraceElement[] arr = TestException.getStackTrace();
for(int i=0;i<=arr.length-1;i++){
System.out.println(arr[i].getClassName()+";"+arr[i].getMethodName()+";"+arr[i].getFileName());
}
}
}
public class App
{
public static void main( String[] args )
{
ThreadTest.TestString();
}
}
运行之后的结果是:
test.TestException;getStackTrace;TestException.java
test.ThreadTest;TestString;ThreadTest.java
test.App;main;App.java
红色的一行即证明了我的想法是正确的!
全部的验证至此结束了。这个问题最后解决的方法非常easy,要么使用new Exception().getStackTrace()[1];要么使用Thread.currentThread().getStackTrace()[2]。
尽管这个问题非常小,也非常基础。可是我还是非常兴奋。毕竟粘上了源代码,顿时逼格升高不少~~~
新手上路。高手饶命~!
得到当前堆栈信息的两种方式(Thread和Throwable)的纠结的更多相关文章
- 26.OpenIdConnect获取用户信息的两种方式
openId在OAuth基础之上,在下面这红框内拿到Authorization Code之后还可以返回IdToken. IdToken和AccessToken一起返回.IdToken就会包括了用户的信 ...
- 程序中使用log4J打印信息的两种方式
(1)通过org.apache.commons.logging.Log 接口实例化: public static Log log = LogFactory.getLog(String name); p ...
- 在Scrapy中如何利用Xpath选择器从HTML中提取目标信息(两种方式)
前一阵子我们介绍了如何启动Scrapy项目以及关于Scrapy爬虫的一些小技巧介绍,没来得及上车的小伙伴可以戳这些文章: 手把手教你如何新建scrapy爬虫框架的第一个项目(上) 手把手教你如何新建s ...
- 读取数据库配置信息的两种方式(以后开发项目用java链接数据库)-------java基础知识
第一步:先建立jdbc.properties user=root password url/yanlong driver=com.mysql.jdbc.Driver 第一种方式:直接文件读取 pack ...
- 删除SVN版本信息的两种方式
一.在linux下删除SVN版本信息 删除这些目录是很简单的,命令如下 find . -type d -name ".svn"|xargs rm -rf 或者 find . -ty ...
- django--通过jwt获取用户信息的两种方式
HTTP请求是无状态的,我们通常会使用cookie或session对其进行状态保持,cookie存储在客户端,容易被用户误删,安全性不高,session存储在服务端,在服务器集群情况下需要解决sess ...
- linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...
- Struts2实现ajax的两种方式
基于Struts2框架下实现Ajax有两种方式,第一种是原声的方式,另外一种是struts2自带的一个插件. js部分调用方式是一样的: JS代码: function testAjax() { var ...
- 在基于MVC的Web项目中使用Web API和直接连接两种方式混合式接入
在我之前介绍的混合式开发框架中,其界面是基于Winform的实现方式,后台使用Web API.WCF服务以及直接连接数据库的几种方式混合式接入,在Web项目中我们也可以采用这种方式实现混合式的接入方式 ...
随机推荐
- 安装Ubuntu服务器
安装edX首先需要一台linux或Mac系统的电脑/服务器. 这里以常见的Ubuntu作为服务器系统. Ubuntu的官方网站为http://www.ubuntu.com,中文网站为http://ht ...
- 获取C#中exe程序的实例名
获取sanjiao.frmsanjiao string strPass = @"D:\WinAutoTest\sanjiao.exe"; Assembly assebly = As ...
- Handler 接收Parcelable ArrayList时返回空的错误
遇到一个问题,从handler 接收的Parcelable ArrayList返回空,调试发现这个arraylist生成的时候是有值的,传到handler就没值了 赋值的代码 new Thread(n ...
- 【POJ】2823 Sliding Window
单调队列. /* 2823 */ #include <iostream> #include <sstream> #include <string> #include ...
- DP录 (更新)
补补弱项 全面发展.. 从最基础来 sdut1299最长上升子序 #include <iostream> #include<cstdio> #include<cstrin ...
- bzoj2756
看到相邻格子都+1的操作一下就想到黑白染色了相邻格子都+1说明不管怎么弄,黑格子的总和和白格子总和的差总是定值这里首先要注意,最后不一定变成的是所有元素中的最大值,可能比它大比如 1 2 2 ...
- c#语言-多线程中的锁系统(一)
介绍 平常在多线程开发中,总避免不了线程同步.本篇就对net多线程中的锁系统做个简单描述. 目录 一:lock.Monitor 1:基础. 2: 作用域. ...
- C#编程实现Excel文档中搜索文本
有了在Word文档中编程实现搜索文本的经验,在Excel中实现这个功能也并非难事. 打开Excel的VBA帮助,查看Excel的对象模型,很容易找到完成这个功能需要的几个集合和对象:Applicati ...
- c语言main函数的参数argc,argv说明
main函数参数argc,argv说明 C/C++语言中的main函数,经常带有参数argc,argv,如下: int main(int argc, char** argv) int main(i ...
- 【转】OS X Mavericks: 防止 Mac 进入睡眠 -- 不错
原文网址:https://support.apple.com/kb/PH13808?locale=zh_CN&viewlocale=zh_CN 某些 Mac 电脑将在不活跃一段时间后自动进入睡 ...