有什么理由在LogBack记录器上使用私有而不是私有的最终静态?

2022-09-01 20:27:14

在弹簧控制器中实例化记录器时,是否有任何理由将其声明为静态最终结果?记录器未在 MyController 外部使用.class。我已经看到了两个正在使用的例子,但不明白为什么我应该使用一个或另一个。

private Logger logger = LoggerFactory.getLogger(MyController.class);

private static final Logger logger = LoggerFactory.getLogger(MyController.class);

答案 1

就个人而言,我使用

private final Logger logger = LoggerFactory.getLogger(this.getClass());

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

至于它们是否应该是静态的,请参阅slf4j网站上的类的Logger成员是否应该声明为静态?,其中说:

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

摘自该页面:

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

  1. 常见且行之有效的成语
  2. 更少的 CPU 开销:在宿主类初始化时,记录器仅检索和分配一次
  3. 更少的内存开销:记录器声明将为每个类消耗一个引用

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

  1. 对于在应用程序之间共享的库,无法利用存储库选择器。应该注意的是,如果 SLF4J 绑定和底层 API 随每个应用程序一起提供(不在应用程序之间共享),则每个应用程序仍将具有自己的日志记录环境。
  2. 对国际奥委会不友好

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

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

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

  1. 比将记录器声明为静态变量更不常见的成语
  2. 更高的 CPU 开销:为宿主类的每个实例检索并分配记录器
  3. 更高的内存开销:记录器声明将为每个宿主类实例消耗一个引用

解释

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

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

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

如果记录器是静态的,则只有在将宿主类加载到内存中时才会检索一次。如果宿主类仅在一个应用程序中使用,则无需担心太多。但是,如果在多个应用程序之间共享宿主类,则共享类的所有实例都将登录到碰巧首先将共享类加载到内存中的应用程序的上下文中 - 这几乎不是用户期望的行为。

有关详细信息,请参阅该页面。


答案 2

将针对类的每个实例初始化仅字段。但是,字段将为每个类初始化一次。privateprivate static

在记录器的情况下(取决于日志记录实现),在这两种情况下,您将获得相同的记录器实例,并且您不会使用明显更大的内存量。但仍然会与您创建的每个对象一起调用。LoggerFactory.getLogger


推荐