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

时间:2011-11-24 20:44:11

标签: java log4j slf4j logback

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

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

VS

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

4 个答案:

答案 0 :(得分:42)

就个人而言,我使用

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

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

至于它们是否应该是静态的,请参阅slf4j网站上的Should Logger members of a class be declared as static?,其中说:

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

摘自该页面:

将记录器声明为静态

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

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

      1. 即使对于应用程序之间共享的库,也可以利用存储库选择器。但是,存储库选择器仅在底层日志记录系统是logback-classic时才有效。存储库选择器不适用于SLF4J + log4j组合。
      2. IOC友好
      3. 将记录器声明为实例变量

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

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

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

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

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

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

答案 1 :(得分:3)

只为您的班级的每个实例初始化private字段。但是,private static字段将在每个类初始化一次。

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

答案 2 :(得分:1)

是;因此,该类只有一个记录器,而不是每个实例一个。

无论哪种方式都是私密的,所以在课外使用它与它无关 - 这不是static final所做的。

答案 3 :(得分:-4)

我只是对这条线感到好奇:

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

是吗:

LoggerFactory.getLogger(MyController.class) 

或:

LoggerFactory.getLogger(MyController.class.getName());

因为第一个将在真实姓名之前返回“class”:

class com.example.MyController (instead of com.example.MyController)