我正在使用的系统中有以下( doctored )类,而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(...);
}
}
但这似乎并不特别有效。
思想?
答案 0 :(得分:19)
首先,不要过早优化。可能LoggerFactory.getLogger()
足够快,并且不会给执行时间带来显着的开销。如果有疑问,请对其进行分析。
其次,findbugs没有抱怨使用Foo
的原因是因为该类没有Foo
类型的字段,它有一个{{1}类型的字段}。泛型在编译时被擦除,就字段定义而言,类中没有实际引用List
。在运行时,如果您尝试序列化Foo
类的实例,Foo
不可序列化的事实会导致异常,但findbugs无法知道这一点。
我的第一反应是将Demo
设为静态字段,而不是实例字段。在这种情况下应该可以正常工作。
Logger
答案 1 :(得分:7)
我不希望事情在切线上起飞,但您是否考虑过传统的记录器初始化?
private static final Logger logger = LoggerFactory.getLogger(Demo.class);
如果你真的不需要为每个实例使用不同的记录器(这是不寻常的),问题就会消失。
顺便说一句,SL4J的author表示(在公共日志记录中的critique Log4J包装中),
通常,这些包装纸 质量可疑,这样的 非活动(或禁用)日志记录的成本 语句乘以一个因子 千分之一(1000)相比 直接log4j用法。最普遍的 包装类中的错误是 调用Logger.getLogger 每个日志请求的方法。这是 保证会对你造成严重破坏 应用程序的性能。真的!!!
这表明不建议您在每次需要时获取记录器的另一种想法。
答案 2 :(得分:6)
在这种特殊情况下,FindBugs会误导您,因为org.slf4j.Logger接口不标记为java.io.Serializable。但是,SLF4J附带的SLF4J记录器实现都支持开箱即用的序列化。试试吧。你会发现它有效。
以下是SLF4j常见问题解答的摘录:
与静态变量相反,实例 变量默认是序列化的。 从SLF4J版本1.5.3开始,记录器 实例在序列化中存活。从而, 序列化的主机类没有 更长时间需要任何特殊行动 即使记录器被声明为 实例变量。在以前 版本,记录器实例需要 在主持人中被宣布为短暂的 类。
答案 3 :(得分:3)
我最初的反应是想知道在对象中序列化Logger实例是否有意义。当您稍后对其进行反序列化时,期望Logger的环境是否正确是否真的公平?我想我宁愿选择这个并称之为一天:
private transient Logger logger = LoggerFactory.getLogger(this.getClass());