16

我正在处理的系统中有以下(修改过的)类,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(...);
    }
}

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

想法?

4

5 回答 5

19

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

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

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

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

   // .. other stuff
}
于 2010-05-10T21:25:38.537 回答
7

我不希望事情一帆风顺,但是您是否考虑过记录器的常规初始化?

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

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

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

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

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

于 2010-05-10T21:33:03.580 回答
6

FindBugs 在这种特殊情况下会误导您,因为 org.slf4j.Logger 接口标记为 java.io.Serializable。但是,SLF4J 附带的 SLF4J 记录器实现都支持开箱即用的序列化。试试看。你会看到它有效。

以下是 SLF4j 常见问题解答的摘录:

与静态变量相反,实例变量默认是序列化的。从 SLF4J 版本 1.5.3 开始,记录器实例在序列化后仍然存在。因此,主机类的序列化不再需要任何特殊操作,即使记录器被声明为实例变量。在以前的版本中,记录器实例需要在宿主类中声明为瞬态。

另见http://slf4j.org/faq.html#declared_static

于 2010-05-12T12:45:13.260 回答
3

我最初的反应是想知道在你的对象中序列化一个 Logger 实例是否有意义。当你稍后反序列化它时,期望 Logger 的环境是正确的真的那么公平吗?我想我宁愿继续这样做,然后收工:

private transient Logger logger = LoggerFactory.getLogger(this.getClass());
于 2010-05-12T13:00:18.250 回答
0

不建议您将记录器放在 Serializable 类中。

以我的经验,它会花费太多的内存。

并且在缓存这个类时很容易导致 OutOfMemory 错误。

继续清理您的可序列化类。

但是,如果您在本地或开发环境中。为自己感到自由。

于 2021-10-14T11:23:07.357 回答