【问题标题】:Any reason to use private instead of private final static on the LogBack Logger?有什么理由在 LogBack Logger 上使用 private 而不是 private final static?
【发布时间】:2011-11-24 20:44:10
【问题描述】:

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

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

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

【问题讨论】:

  • 最好完全摆脱这个变量并使用jcabi-log中的Logger,它是SLF4J的静态包装器

标签: java log4j slf4j logback


【解决方案1】:

我个人使用

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

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

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

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

取自该页面:

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

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

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

  1. 对于应用程序之间共享的库,无法利用存储库选择器。需要注意的是,如果 SLF4J 绑定和底层 API 随每个应用程序一起提供(不是在应用程序之间共享),那么每个应用程序仍然有自己的日志记录环境。
  2. 不适合 IOC

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

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

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

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

说明

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

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

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

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

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

【讨论】:

  • 关于 this.getClass() 的好提示
  • 对静态部分的解释很好,但最后部分呢? 'static final' 优先于 'static' 吗?谢谢。
  • @Dimitri Dewaele 对于记录器,使用 final 并立即对其进行初始化。通过这种方式,您可以防止出现 NPE 之类的情况,因为您忘记了对其进行初始化。一个例外是当您确切地想要更改记录器时。例如,您可能希望将其替换为间谍记录器,以在单元测试期间验证您生成的日志消息。
  • 为了不复制和粘贴,您可以使用代码模板。所有现代 ide 都支持它。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    是的;所以这个类只有一个记录器,而不是每个实例一个。

    无论如何它都是私有的,所以在课堂之外使用它与它无关——这不是static final 所做的。

    【讨论】:

      【解决方案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) 
      

      【讨论】:

      • 这是一个问题,而不是一个答案
      猜你喜欢
      • 2012-11-04
      • 2013-05-23
      • 1970-01-01
      • 2022-08-22
      • 2015-07-28
      • 2011-07-02
      • 1970-01-01
      • 1970-01-01
      • 2012-01-18
      相关资源
      最近更新 更多