Logback中Debug禁用时toString()是否会被调用?性能咨询
这个问题其实戳中了Java方法调用和日志框架实现的一个关键点,我来给你掰扯清楚:
首先明确:Debug禁用时,toString()这类方法仍然会被执行
Java的方法调用规则是:在调用任何方法(包括logger.debug())之前,会先把所有传入的实参都计算出来。也就是说,不管Logback内部要不要输出日志,object.value()和object.toString()都会先执行,把结果算出来再传给logger.debug()。
Logback的大括号占位符只是避免了字符串拼接的性能损耗(比如不用"xxx" + object.value()这种会生成中间字符串的写法),但它管不了参数本身的执行——因为参数计算发生在Logback方法调用之前,和Logback的逻辑无关。
那能不能继续用这种写法?分两种情况看:
- 如果你的
toString()或者其他参数方法逻辑很简单(比如只是返回几个字段的拼接,没有复杂计算、DB查询之类的),那其实性能影响微乎其微,继续用也没问题,代码可读性还更好。 - 但如果这些方法有较重的逻辑(比如遍历集合、调用其他服务、序列化对象),那Debug禁用时的无效执行就会浪费资源,这时候就不建议直接这么写了,推荐两种优化方式:
方案1:先判断日志级别,再调用debug
这是最传统也最稳妥的写法,只有当Debug级别开启时,才会计算参数并输出日志:
if (logger.isDebugEnabled()) { logger.debug(" My class output value - {}, object toString() {}", object.value(), object.toString()); }
方案2:用Logback的延迟加载特性(Logback 1.2.0+支持)
Logback从1.2.0版本开始支持Supplier类型的参数,你可以用Lambda表达式把参数包装起来,这样只有当日志级别允许输出时,才会执行Lambda里的逻辑:
logger.debug(" My class output value - {}, object toString() {}", object.value(), () -> object.toString());
这里() -> object.toString()就是一个Supplier,Logback会在确定要输出日志的时候才调用它的get()方法,也就是才会执行object.toString(),完美避免了无效执行。
总结
如果参数方法的性能开销可以忽略,继续用原写法没问题;如果有性能顾虑,就用上面两种优化方案。核心要记住:Logback的占位符只解决字符串拼接问题,解决不了参数提前执行的问题——这是Java语言本身的机制决定的。
内容的提问来源于stack exchange,提问作者Shriram
相关产品推荐
相关产品推荐

