为什么Logger大部分时间都是静态的?

时间:2015-08-09 22:26:53

标签: java oop logging static

为什么将Loggerstatic一起用作java中的“最佳做法”:

public static final Logger LOGGER = LoggerFactory.getLogger(....)

我无法想出共鸣的原因。如果我使用一个记录器实例并通过构造函数传递它,它不应该影响性能。

任何人都可以解释原因吗? DI比它更好吗?如果是这样,为什么?有很多意见。或者只是“因为java方式”?

4 个答案:

答案 0 :(得分:3)

防止不必要地创建多个实例。通常,单个Logger就足够了,因为它写入单个逻辑位置(可能是多个物理输出流)。如果您将Logger传递给方法,则可能以编程方式处理日志记录。相反,我建议您更喜欢记录器自己的配置机制来启用和禁用消息传递。

答案 1 :(得分:2)

我认为使用 setter injection 依赖注入容器可以获得相同的结果。

你仍然可以拥有非常简单的日志记录,它只是不是静态的,因此可以在DI容器中进行配置和更改,而无需配置某些全局静态工厂的全局静态状态,这通常很难测试和维护

然而,我知道让它静止是务实的。我只是在争论这样做DI方式更清洁。

答案 2 :(得分:1)

这是因为正确进行日志记录非常困难。 Consider the single responsibility principle

  

在面向对象的编程中,单一责任原则规定每个类应对软件提供的单个功能部分负责,并且该责任应完全由类封装。它的所有服务都应该与这一责任保持一致。

但是,如果您考虑一下,管理日志记录的代码永远不会成为类的主要责任。该类将执行它的功能,然后您可能会添加一些记录该类的第二责任的语句。怎么解决这个问题?

一种方法是使用Aspect Oriented Programming和反射来完成代码并尝试记录活动,但这很难看,需要加入语言。另一种方法是将Logger个对象添加到类的构造中,但这有一些缺点:

  1. 如果您使用DI框架,则只能在不添加批量样板的情况下执行此操作
  2. 您仍然需要以某种方式配置Logger的名称,这意味着注入现在取决于它被注入的类。
  3. 同样,如果您没有使用DI框架,那么您必须在创建对象时以某种方式维护对同一Logger对象的访问,否则您最终会创建许多重复内存的对象,没有优势,这是更多的样板代码。
  4. 那么,该怎么办? 最简单的方式是允许所有类对Logger对象进行静态访问。正确指出,SLF4J为LoggerFactory.getLogger()提供了这种机制。它是一行代码,可以使用Factory Pattern在所有类中实现完全可自定义的行为,以使用日志记录功能。你不必担心注射,反思,配置AOP;它简单,直接,有效。

答案 3 :(得分:0)

私有 - 所以没有其他类可以劫持你的记录器

static - 所以每个类只有一个记录器实例,也避免了尝试序列化记录器

final - 无需在类的生命周期内更改记录器

然而,这些规则有一个有趣的例外:

protected final Logger log = LoggerFactory.getLogger(getClass());

前一种方法允许您在整个继承层次结构中的所有类中使用相同的记录器名称(实际类的名称)。因此,如果Bar扩展Foo,两者都将记录到Bar logger。有些人觉得它更直观。

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

然而,它的缺点显然是将为该类的每个实例创建一个全新的记录器实例。

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

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