有什么理由在LogBack Logger上使用private而不是private final static?

Tom*_*mmy 24 java log4j logback slf4j

在Spring Controller中实例化Logger时,有没有理由将它声明为静态final?LogConger不在MyController.class之外使用.我已经看到两个例子在使用,但不明白为什么我应该使用其中一个.

private Logger logger = LoggerFactory.getLogger(MyController.class);
Run Code Online (Sandbox Code Playgroud)

VS

private static final Logger logger = LoggerFactory.getLogger(MyController.class);
Run Code Online (Sandbox Code Playgroud)

Mat*_*ell 43

就个人而言,我用

private final Logger logger = LoggerFactory.getLogger(this.getClass());
Run Code Online (Sandbox Code Playgroud)

这样做的主要优点是我可以将其剪切并粘贴到新类中,而无需更改类的名称.

至于它们是否应该是静态的,请看一个类的Logger成员是否被声明为静态?,来自slf4j网站,其中说:

我们曾经建议将记录器成员声明为实例变量而不是静态变量.经过进一步分析,我们不再推荐一种方法而不是另一种方法.

摘自该页面:

将记录器声明为静态的优点

  1. 共同的,成熟的习语
  2. 减少CPU开销:在托管类初始化时检索记录器并仅分配一次
  3. 内存开销减少:记录器声明将为每个类消耗一个引用

将记录器声明为静态的缺点

  1. 对于应用程序之间共享的库,不可能利用存储库选择器.应该注意的是,如果SLF4J绑定和底层API随每个应用程序一起提供(不在应用程序之间共享),那么每个应用程序仍将拥有自己的日志记录环境.
  2. 不是IOC友好的

将记录器声明为实例变量的优点

  1. 即使对于应用程序之间共享的库,也可以利用存储库选择器.但是,存储库选择器仅在底层日志记录系统是logback-classic时才有效.存储库选择器不适用于SLF4J + log4j组合.
  2. 国际奥委会友好

将记录器声明为实例变量的缺点

  1. 比将logger声明为静态变量更不常见的习惯用法
  2. 更高的CPU开销:检索记​​录器并为托管类的每个实例分配记录器
  3. 更高的内存开销:logger声明将为每个托管类实例使用一个引用

说明

静态记录器成员为该类的所有实例花费单个变量引用,而实例记录器成员将为该类的每个实例花费一个变量引用.对于实例化数千次的简单类,可能会有明显的差异.

但是,更新的日志记录系统(例如log4j或logback)为应用程序服务器中运行的每个应用程序支持不同的记录器上下文.因此,即使在服务器中部署了log4j.jar或logback-classic.jar的单个副本,日志记录系统也能够区分应用程序并为每个应用程序提供独特的日志记录环境.

更具体地说,每次通过调用LoggerFactory.getLogger()方法检索记录器时,底层日志记录系统将返回适合当前应用程序的实例.请注意,在同一应用程序中,按给定名称检索记录器将始终返回相同的记录器.对于给定名称,将仅为不同的应用程序返回不同的记录器.

如果记录器是静态的,那么只有在将宿主类加载到内存中时才会检索它.如果托管类仅在一个应用程序中使用,则没有太多需要关注的问题.但是,如果托管类在多个应用程序之间共享,那么共享类的所有实例都将登录到应用程序的上下文,该应用程序恰好首先将共享类加载到内存中 - 几乎不是用户期望的行为.

有关更多信息,请参阅该页面.

  • @Dimitri Dewaele对于记录器,使用final并立即初始化它.这样,您可以防止任何像NPE这样的情况,因为您忘记了初始化它.一个例外是当你想要更改记录器时.例如,您可能希望用间谍记录器替换它,以在单元测试期间验证生成的日志消息. (4认同)
  • 关于this.getClass()的好建议 (2认同)