在可序列化的Java类中使用记录器的正确方法是什么?

2022-09-03 04:33:57

我在我正在处理的系统中有以下(篡改)类,Findbugs正在生成一个SE_BAD_FIELD警告,我试图理解为什么它会在我以我认为的方式修复它之前说。我感到困惑的原因是,描述似乎表明我在类中没有使用其他不可序列化的实例字段,但bar.model.Foo也是不可序列化的,并且以完全相同的方式使用(据我所知),但Findbugs没有生成任何警告。

import bar.model.Foo;

import java.io.File;
import java.io.Serializable;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo implements Serializable {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final File file;
    private final List<Foo> originalFoos;
    private Integer count;
    private int primitive = 0;

    public Demo() {
        for (Foo foo : originalFoos) {
            this.logger.debug(...);
        }
    }

    ...

}

我对解决方案的最初反应是,在我使用它时从工厂获取记录器参考:

public DispositionFile() {
    Logger logger = LoggerFactory.getLogger(this.getClass());
    for (Foo foo : originalFoos) {
        this.logger.debug(...);
    }
}

不过,这似乎并不是特别有效。

思潮?


答案 1

首先,不要过早优化。它可能足够快,并且不会对执行时间造成重大开销。如有疑问,请对其进行剖析。LoggerFactory.getLogger()

其次,findbugs没有抱怨使用的原因是因为类没有类型的字段,它有一个类型的字段。泛型在编译时被擦除,就字段定义而言,类中没有实际的引用。在运行时,如果您尝试序列化类的实例,则不可序列化的事实将导致异常,但 findbugs 无法知道这一点。FooFooListFooFooDemo

我的第一反应是使字段成为静态字段,而不是实例字段。在这种情况下应该工作正常。Logger

public class Demo implements Serializable {
   private static final Logger logger = LoggerFactory.getLogger(Demo.class);

   // .. other stuff
}

答案 2

我不希望事情在切线上起飞,但是您是否考虑过记录器的传统初始化?

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

如果您真的不需要为每个实例使用不同的记录器(这是不寻常的),那么问题就会消失。

顺便说一句,SL4J的作者说(在对Log4J包装器的批评中,如commons-logging),

通常情况下,这些包装器的质量令人怀疑,因此与直接使用log4j相比,非活动(或禁用)日志记录语句的成本乘以1'000(一千)。包装类中最常见的错误是在每个日志请求上调用 Logger.getLogger 方法。这肯定会对应用程序的性能造成严重破坏。真!!!

这表明,不建议在每次需要时获取记录器的替代想法。