在独立的Java应用程序中使用相同的log4j logger

shi*_*ike 3 java log4j

我有一些代码是一个包含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();
    }
}
Run Code Online (Sandbox Code Playgroud)

A)我的问题是这是否应该重构为一些初始化一次并被所有类使用的常见记录器?这是一种更好的做法吗?

B)如果是,怎么办?我怎样才能通过记录器?

C)这实际上是被在代码中使用不作为Logger.debug(),但getLogger().debug().这在绩效方面有何影响?

Pét*_*rök 8

A)在Log4J中,您有记录器层次结构,而不是单个记录器.这通常归结为每个类一个记录器,其中记录器由类名标识.记录器初始化如下:

private static final Logger logger = Logger.getLogger(MyClass.class);
Run Code Online (Sandbox Code Playgroud)

这是一个很好的做法,它允许您微调模块(包)甚至应用程序中各个类的日志记录行为.因此,您可以禁用某些软件包的日志记录,在其他软件包中记录INFO级别,并在某些关键类中登录DEBUG级别,例如,当您想要捕获错误时.

B)但是,如果您想在任何地方使用单个记录器,只需在每个类中使用根记录器:

private static final Logger logger = Logger.getLogger();
Run Code Online (Sandbox Code Playgroud)

C)对于不太复杂的方法的调用,性能差异可能是微不足道的,因为JIT编译器无论如何都会积极地内联调用.对于复杂的方法,它更像是一个悬而未决的问题.

请注意,您显示的方法通过加载记录器配置来执行不必要的工作 - 如果您将配置文件命名log4j.properties并将其放在类路径上,则由Log4J自动完成.但是,即使您需要使用非标准配置文件名,仍然可以在启动时在一个位置加载Log4J配置,并省略延迟加载记录器.那剩下的就是

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

private static Logger getLogger() {
    return logger;
}
Run Code Online (Sandbox Code Playgroud)

这肯定会被编译器内联.getLogger尽管如此,您可能希望保留,以避免修改大量的调用者代码.

请注意,没有getLogger必要这样做public,因为所有类都应该有自己的记录器引用.