我有一些代码是一个包含30多个类的独立java应用程序。
其中大多数都继承自其他一些基类。
每个类都有此方法来获取和使用log4j记录器
public static Logger getLogger() {
if (logger != null) return logger;
try {
PropertyUtil propUtil = PropertyUtil.getInstance("app-log.properties");
if (propUtil != null && propUtil.getProperties() != null)
PropertyConfigurator.configure(propUtil.getProperties ());
logger = Logger.getLogger(ExtractData.class);
return logger;
} catch (Exception exception) {
exception.printStackTrace();
}
}
A)我的问题是这是否应该重构为一些初始化一次并被所有类使用的常见记录器?这是一种更好的做法吗?
B)如果是,怎么办?我怎样才能通过记录器?
C)这实际上在代码中使用的不是Logger.debug()
而是getLogger().debug()
。
这在绩效方面有何影响?
答案 0 :(得分:8)
A)在Log4J中,您有记录器层次结构,而不是单个记录器。这通常归结为每个类一个记录器,其中记录器由类名标识。记录器初始化如下:
private static final Logger logger = Logger.getLogger(MyClass.class);
这是一个很好的做法,它允许您微调模块(包)甚至应用程序中各个类的日志记录行为。因此,您可以禁用某些软件包的日志记录,在其他软件包中记录INFO级别,并为某些关键类别登录DEBUG级别,例如:当你想捕捉到一个bug时。
B)但是,如果您想在任何地方使用单个记录器,只需在每个类中使用根记录器:
private static final Logger logger = Logger.getLogger();
对于不太复杂的方法的调用,性能差异可能微不足道,因为JIT编译器无论如何都会积极地内联调用。对于复杂的方法,这更像是一个悬而未决的问题。
请注意,您显示的方法通过加载记录器配置执行了不必要的工作 - 如果您将配置文件命名为log4j.properties
并将其放在类路径上,则由Log4J自动完成。但是,即使您需要使用非标准配置文件名,仍然可以在启动时在一个位置加载Log4J配置,并省略延迟加载记录器。那么剩下的就是
private static final Logger logger = Logger.getLogger(ExtractData.class);
private static Logger getLogger() {
return logger;
}
这肯定会由编译器内联。您可能仍希望保留getLogger
,以避免修改大量的来电代码。
请注意,getLogger
不必是public
,因为所有类都应该有自己的记录器参考。
答案 1 :(得分:3)
A)取决于,但我认为每类记录器的粒度是使用log4j的实用程序的一部分。如果需要,可以从一个类重定向日志信息,或者将它们全部发送到同一个文件。
B)你不会传递记录器,你只需使用Logger.getLogger()
方法来使用根记录器。
C)在性能方面可能不大。如果它还不是静态的,则可以选择将getLogger()
方法指示为final
,以表明它应该内联。彼得的答案在这里更好,正如他所指出的,如果方法足够简单,那么无论如何都可能会内联。
答案 2 :(得分:0)
每个类都可以将它自己的记录器作为
final static private Logger log = Logger.getLogger("com.company.package.MyClass");
这使您可以按类调整log4j设置,这比标准记录器更灵活。