代码之家  ›  专栏  ›  技术社区  ›  Tim Visher

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

  •  15
  • Tim Visher  · 技术社区  · 14 年前

    我有以下内容( 篡改 )在我正在研究的系统中上课 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 回复  |  直到 14 年前
        1
  •  18
  •   skaffman    14 年前

    首先,不要过早优化。可能是 LoggerFactory.getLogger() 速度足够快,并且不会对执行时间造成重大开销。如果有疑问,请描述一下。

    其次,findbugs不抱怨使用 Foo 是因为类没有类型为的字段 ,它有一个类型的字段 List . 泛型在编译时被删除,没有实际引用 在类中,就字段定义而言。在运行时, 如果尝试序列化 Demo 类,但findbugs不知道这一点。

    我的第一反应是 Logger 静态字段,而不是实例字段。在这种情况下应该工作得很好。

    public class Demo implements Serializable {
       private static final Logger logger = LoggerFactory.getLogger(Demo.class);
    
       // .. other stuff
    }
    
        2
  •  7
  •   Community WizardZ    7 年前

    我不希望事情发生在切线上,但是您考虑过记录器的常规初始化吗?

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

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

    顺便说一下, author SL4J的 critique 在log4j包装器中,如commons logging)。

    通常,这些包装纸 质量可疑,以致 非活动(或禁用)日志记录的成本 语句乘以因子 与 直接使用log4j。最常见 包装类中的错误是 调用logger.getlogger 每个日志请求的方法。这是 保证会对你的 应用程序的性能。真的?!!!

    这就意味着,不建议您在每次需要日志时都使用它。

        3
  •  6
  •   Ceki    14 年前

    在这种特殊情况下,findbugs会误导您,因为org.slf4j.logger接口是 标记为java.io.serializable。但是,与slf4j一起提供的slf4j记录器实现都支持现成的序列化。试试看。你会看到它起作用的。

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

    与静态变量相反,实例 默认情况下,变量是序列化的。 从SLF4J 1.5.3版开始,记录器 实例在序列化之后仍然存在。因此, 主机类的序列化否 更长的时间需要任何特殊行动, 即使记录员被宣布为 实例变量。在以前 需要的版本、记录器实例 在主机中声明为瞬态 班级。

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

        4
  •  3
  •   Ophidian    14 年前

    我最初的反应是想知道在对象中序列化记录器实例是否有意义。当您稍后反序列化它时,期望记录器的环境是正确的,这真的很公平吗?我想我宁愿带着这个走,结束它:

    private transient Logger logger = LoggerFactory.getLogger(this.getClass());