欢迎访问 生活随笔!

凯发ag旗舰厅登录网址下载

当前位置: 凯发ag旗舰厅登录网址下载 > 编程语言 > c# >内容正文

c#

java 面试题之 logback 打印日志是如何获取当前方法名称的? -凯发ag旗舰厅登录网址下载

发布时间:2023/11/12 c# 38 coder
凯发ag旗舰厅登录网址下载 收集整理的这篇文章主要介绍了 java 面试题之 logback 打印日志是如何获取当前方法名称的? 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

在 java 中,有四种方法可以获取当前正在执行方法体的方法名称,分别是:

  1. 使用 thread.currentthread().getstacktrace() 方法
  2. 使用异常对象的 getstacktrace() 方法
  3. 使用匿名内部类的 getclass().getenclosingmethod() 方法
  4. java 9 的 stack-walking api

本文将根据以上四种方法来给大家进行具体讲解,不过不知道大家有没有想过,获取当前执行方法体的方法名称有什么用嘞?

它可以用于日志记录、异常处理、测试框架等方面。例如我们可以在方法的开始和结束时打印出当前方法名和参数,以便追踪程序的执行流程和性能。在介绍完以上四种方法后,就会给大家揭晓面试题答案。

1.使用 thread.currentthread().getstacktrace()方法

这种方法是通过获取当前线程的堆栈跟踪信息,然后从中提取出当前方法名的。具体的代码如下:

// 获取当前方法名
string methodname = thread.currentthread().getstacktrace()[1].getmethodname();
// 打印当前方法名
system.out.println("当前方法名:"   methodname);

这种方法的优点是简单易用,不需要创建额外的对象。缺点是性能较低,因为 thread.currentthread().getstacktrace() 方法获取堆栈跟踪信息需要遍历整个调用栈,而且需要保证线程安全性。

2.使用异常对象的 getstacktrace()方法

这种方法是通过创建一个新的异常对象,然后从其堆栈跟踪信息中提取出当前方法名和参数的。具体的代码如下:

// 获取当前方法名
string methodname = new exception().getstacktrace()[0].getmethodname();
// 打印当前方法名
system.out.println("当前方法名:"   methodname);

这种方法的优点是不需要获取堆栈跟踪信息,而且不会创建异常对象,因此性能和可读性都较好。缺点是需要创建额外的对象,而且代码较为复杂,不太直观。

3.匿名内部类的 getclass().getenclosingmethod()方法

这种方法是通过创建一个匿名内部类的对象,然后从其类对象中获取当前方法的方法对象,再从方法对象中获取当前方法名和参数的。具体的代码如下:

// 获取当前方法名
string methodname = new object(){}.getclass().getenclosingmethod().getname();
// 打印当前方法名
system.out.println("当前方法名:"   methodname);

这种方法的优点是不需要获取堆栈跟踪信息,而且不会创建异常对象,因此性能和可读性都较好。缺点是需要创建额外的对象,而且代码较为复杂,不太直观。

4.java 9 的 stack-walking api

java 9 引入了 stack-walking api,以惰性且高效的方式遍历 jvm 堆栈帧。可以使用这个 api 找到当前正在执行的方法,具体的代码如下:

stackwalker walker = stackwalker.getinstance();
optional optional = walker.walk(frames -> frames
        .findfirst()
        .map(stackwalker.stackframe::getmethodname));
system.out.println("当前方法名:"   optional.get());

首先,我们使用 stackwalker.getinstance() 工厂方法获取 stackwalker 实例。然后我们使用 walk() 方法从上到下遍历栈帧:

  • walk() 方法可以将堆栈帧转化为 stream
  • findfirst() 方法从 stream 流中的获取第一个元素,也就是堆栈的顶部帧,顶部帧就代表当前正在执行的方法
  • map() 方法用于获取顶部帧 stackframe 的当前方法名称

stack-walking api 的优点

与以上方法相比,stack-walking api 有很多优点:

  • 线程安全
  • 无需创建匿名内部类实例 - new object().getclass(){}
  • 无需创建异常 - new throwable()
  • 无需急切地捕获整个堆栈跟踪,这可能成本很高 - thread.currentthread()

stackwalker 是以一种懒惰的方式逐一遍历堆栈。在需要获取当前方法名称时,我们可以只获取顶部帧,而不需要捕获整个堆栈跟踪。

推荐作者开源的 h5 商城项目 waynboot-mall,这是一套全部开源的微商城项目,包含三个项目:运营后台、h5 商城前台和服务端接口。实现了商城所需的凯发ag旗舰厅登录网址下载首页展示、商品分类、商品详情、商品 sku、分词搜索、购物车、结算下单、支付宝/微信支付、收单评论以及完善的后台管理等一系列功能。 技术上基于最新得 springboot3.0、jdk17,整合了 mysql、redis、rabbitmq、elasticsearch 等常用中间件。分模块设计、简洁易维护,欢迎大家点个 star、关注我。

github 地址:https://github.com/wayn111/waynboot-mall

经典例子:logback

logback 是一个流行的 java 日志框架,它是 log4j 的继承者,由 log4j 的创始人设计。logback 有以下特点:

  • 高性能:logback 比其他日志框架更快,更节省空间,有时甚至大得多。
  • 灵活配置:logback 支持 xml 和 groovy 两种配置方式,可以实现动态修改配置,无需重启应用。
  • 丰富功能:logback 提供了多种输出目标,如控制台、文件、数据库、邮件等,还支持滚动策略、过滤器、异步日志等高级功能。
  • 与 slf4j 集成:logback 是 slf4j 的原生实现,可以与其他基于 slf4j 的日志框架无缝切换。

不知道大家有没有想过,我们在使用 logback 日志框架中打印日志时,是如何获取当前执行方法体的方法名称的嘞?在 spring 项目中,我们一般是通过 logback 的 xml 文件 parttern 属性来配置日志格式的。xml 配置如下:



    
    
    
    
    
        
        
            ${pattern}
        
    
    
    
        ${logpath}/info.log
        
            ${pattern}
        
        
            ${logpath}/run.%d{yyyy-mm-dd}.log
        
    
    ...

可以看到我们配置的日志输出格式是 %d{yyyy-mm-dd hh:mm:ss.sss} [%x{request_id}] [%thread] [%-5level] %logger{36}:%l %m - %msg%n,logback 在打印日志时,会解析这个日志输出格式,最后将 %m 占位符替换为当前方法名称。

解析日志格式的源码就在 formattingconverter 类的 write() 方法中,write() 方法中会执行 convert() 方法,这个方法就是执行占位符替换的。源码截图如下,

如上图根据类名我们可以看到红线框起来的 methodofcallerconverter 类就是用来执行 %m 占位符替换逻辑的,代码如下,

public class methodofcallerconverter extends classicconverter {
    public string convert(iloggingevent le) {
        stacktraceelement[] cda = le.getcallerdata();
        if (cda != null && cda.length > 0) {
            // 返回当前方法名称
            return cda[0].getmethodname();
        } else {
            return coreconstants.na;
        }
    }
}

方法逻辑如下,

  1. stacktraceelement[] cda = le.getcallerdata() 获取当前堆栈顶部帧
  2. cda[0].getmethodname() 根据顶部帧获取当前方法名称。

如上,我们只需要看下 le.getcallerdata() 方法的堆栈是从哪里获取来的,就能知道本题的答案了。

进入 loggingevent 源码类中,我们可以发现堆栈获取逻辑,源码如下,

public class loggingevent implements iloggingevent {
    public stacktraceelement[] getcallerdata() {
        if (callerdataarray == null) {
            // 堆栈初始化
            callerdataarray = callerdata.extract(new throwable(), fqnofloggerclass,
                    loggercontext.getmaxcallerdatadepth(), loggercontext.getframeworkpackages());
        }
        return callerdataarray;
    }
    ...
}
  1. 如果当前堆栈为空,进行堆栈信息初始化。这里就可以看到堆栈信息初始化来自 callerdata.extract(new throwable(), fqnofloggerclass,loggercontext.getmaxcallerdatadepth(), loggercontext.getframeworkpackages()) 方法。
  2. 如果堆栈信息不为空,直接返回当前堆栈。这里是为了避免浪费,针对在一个方法中重复获取堆栈信息的情况。

ok,到这里离胜利就只差一步了。进一步查看 callerdata.extract(new throwable(), fqnofloggerclass,loggercontext.getmaxcallerdatadepth(), loggercontext.getframeworkpackages()) 方法,源码如下,

public class callerdata {
    public static stacktraceelement[] extract(throwable t, string fqnofinvokingclass, final int maxdepth,
            list frameworkpackagelist) {
        if (t == null) {
            return null;
        }
        stacktraceelement[] stearray = t.getstacktrace();
        stacktraceelement[] callerdataarray;
        ...
        callerdataarray = new stacktraceelement[desireddepth];
        for (int i = 0; i < desireddepth; i  ) {
            callerdataarray[i] = stearray[found   i];
        }
        return callerdataarray;
    }
    ...
}

为了突出源码逻辑的重点,这里我删去了一部分代码,是为了让大家更好的看清楚 logback 中堆栈信息的初始化,其实用的就是异常对象的 getstacktrace() 方法。也就是上面源码中 stacktraceelement[] stearray = t.getstacktrace() 方法所体现的。

那么到这里我就可以下一个结论了, logback 日志框架中打印日志时,就是使用异常对象的 getstacktrace() 方法来获取当前执行方法的方法名称的。

总结

本文有介绍四种方法获取当前执行方法名称,一般情况下大家使用异常对象的 getstacktrace() 方法以及匿名内部类的 getclass().getenclosingmethod() 方法都是可以的,它们的性能都 ok,代码书写复杂程度都大差不差。在 java 9 以后推荐使用 stack-walking api,它的功能更为强大,与程序里的堆栈语意也跟为契合,性能 ok,并且还是线程安全的。

关注公众号【waynblog】每周分享技术干货、开源项目、实战经验、国外优质文章翻译等,您的关注将是我的更新动力!

总结

以上是凯发ag旗舰厅登录网址下载为你收集整理的java 面试题之 logback 打印日志是如何获取当前方法名称的?的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发ag旗舰厅登录网址下载网站内容还不错,欢迎将凯发ag旗舰厅登录网址下载推荐给好友。

  • 上一篇:
  • 下一篇:
网站地图