每个实例的记录器,不好的做法?

Logger per instance, bad practice?

我有一个 class(示例 FileConfig),它在程序的许多不同地方使用,class 也是其(插件)API 的一部分。所以 class 应该非常通用并且可以广泛使用。我想在此 class 中使用 Logger (java.util.logging.Logger)。每个 class 使用一个 private static final Logger 实例似乎是最佳实践,如许多代码示例所示。在我看来,这对我来说是非常不灵活的。我可以想到我或使用 API 的人想要为程序的特定部分使用不同的 Logger 实例的情况。下面的代码展示了我解决这个问题的思路。

import java.util.logging.Logger;

public class FileConfig {
    private static final Logger LOGGER = Logger.getLogger(FileConfig.class.getName());
    private Logger logger = LOGGER;

    public void setLogger(Logger logger) {
        if (logger == null) {
            throw new IllegalArgumentException("logger cannot be null");
        }

        this.logger = logger;
    }
}

这使得每个实例可以使用不同的 Logger,而默认行为仍然与仅具有 static Logger 字段相同。这段代码有什么问题吗?我有理由避免这种情况吗?无论出于何种原因,这种做法都是不好的吗?如果是,为什么?我也非常感谢您对此的个人意见或建议如何改进它。

Are there any problems with this code?

使用记录器的线程和更改记录器的线程之间没有线程安全协调。没有说明使用假设的 JavaDoc。

Is there a reason why I should avoid that?

拥有一个可以在构造后调用的方法 setLogger 可能允许消息在处理程序之间被撕裂。更改 class 的记录器似乎需要权限检查。

I would also appreciate your personal opinion about this or suggestion how to improve it.

您不禁止子 classes,因此检查 class 名称可能更安全:

import java.util.logging.Logger;

public class FileConfig {
    private final Logger logger = Logger.getLogger(getClass().getName());
}

想要使用不同记录器的调用者可以子class 'FileConfig'。这允许在调用者的命名空间中创建子class,这通常是您在组合对象时想要实现的。