记录器应该是私有静态还是非静态

时间:2010-10-01 20:26:00

标签: java logging

记录器是否应声明为静态?通常我会看到两种类型的记录器声明:

    protected Log log = new Log4JLogger(aClass.class);

    private static Log log = new Log4JLogger(aClass.class);

应该使用哪一个?这两者的专业和概念是什么?

4 个答案:

答案 0 :(得分:92)

非静态表单的优点是您可以在(抽象)基类中声明它,如下所示,而不必担心将使用正确的类名:

protected Log log = new Log4JLogger(getClass());

然而,它的缺点显然是将为该类的每个实例创建一个全新的记录器实例。这可能本身并不昂贵,但它增加了很大的开销。如果您想避免这种情况,则需要使用static表单。但它的缺点反过来是你必须在每个单独的类中声明它并注意在记录器构造期间使用了正确的类名的每个类,因为getClass()不能在静态上下文中使用。但是,在普通的IDE中,您可以为此创建自动完成模板。例如。 logger + ctrl+space

另一方面,如果您通过工厂获取记录器,而工厂又可以缓存已经实例化的记录器,那么使用非静态表单不会增加太多开销。例如,Log4j为此目的有一个LogManager

protected Log log = LogManager.getLogger(getClass());

答案 1 :(得分:43)

我曾经认为所有记录器都应该是静态的;但是,this article at wiki.apache.org提出了一些关于类加载器泄漏的重要内存问题。将logger声明为static会阻止声明类(和关联的类加载器)在使用共享类加载器的J2EE容器中进行垃圾回收。如果您重新部署应用程序足够多次,这将导致PermGen错误。

除了将记录器声明为非静态外,我真的没有办法解决这个类加载器泄漏问题。

答案 2 :(得分:15)

最重要的区别在于它如何影响您的日志文件:日志在哪个类别中?

  • 在您的第一个选择中,子类的日志最终会出现在超类的类别中。这对我来说似乎非常违反直觉。
  • 您的第一个案例有一个变体:

    protected Log log = new Log4JLogger(getClass());

    在这种情况下,您的日志类别会说明记录的代码正在处理哪个对象。

  • 在您的第二个选择(私有静态)中,日志类别是包含日志记录代码的类。通常是正在记录事物的类。

我强烈建议最后一个选项。与其他解决方案相比,它具有以下优势:

  • 日志和代码之间存在直接关系。很容易找回日志消息的来源。
  • 如果有人必须调整日志记录级别(按类别完成),通常是因为他们对特定类所写的某些特定消息感兴趣(或不感兴趣)。如果类别不是编写消息的类,则调整级别会更难。
  • 您可以登录静态方法
  • 记录器只需要每个类初始化(或查找)一次,因此在启动时,而不是每个创建的实例。

它也有缺点:

  • 需要在记录消息的每个类中声明它(不重用超类记录器)。
  • 初始化记录器时,需要注意设置正确的类名。 (但好的IDE会为你解决这个问题)。

答案 3 :(得分:3)

使用控制反转并将记录器传递给构造函数。如果你在课堂上创建了记录器,那么你的单元测试将会有一段时间。你在写单元测试不是吗?