Каков правильный способ использования Logger в классе Serializable Java?

У меня есть следующий (доктрированный) класс в системе, над которой я работаю, и 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(...);
        }
    }

    ...

}

Мой первоначальный румянец в решении заключается в том, чтобы получить ссылку на журнал с помощью factory вправо, когда я его использую:

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

Это не кажется особенно эффективным.

Мысли?

Ответы

Ответ 1

Во-первых, не оптимизируйте преждевременно. Может быть, LoggerFactory.getLogger() достаточно быстр и не вносит существенных накладных расходов на время выполнения. Если есть сомнения, профайл.

Во-вторых, причина, по которой findbugs не жалуется на использование Foo, заключается в том, что класс не имеет поля типа Foo, он имеет поле типа List. Дженерики стираются во время компиляции, нет фактической ссылки на Foo в классе, что касается определения поля. Во время выполнения тот факт, что Foo является несериализуемым, вызовет исключение, если вы попытаетесь сериализовать экземпляр класса Demo, но findbugs не могут этого знать.

Моя первая реакция состояла в том, чтобы сделать 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),

Чаще всего эти обертки имеют сомнительное качество, так что стоимость неактивного (или отключенного) ведения журнала операторы умножаются на коэффициент 1 000 (одна тысяча) по сравнению с прямое использование log4j. Самый распространенный ошибка в классах-оболочках вызов Logger.getLogger метод для каждого запроса журнала. Это гарантировано нанести ущерб вашей производительность приложения. Действительно!!!

Это предполагает, что ваша альтернативная идея получения регистратора каждый раз, когда вам это нужно, не рекомендуется.

Ответ 3

FindBugs вводит вас в заблуждение в этом конкретном случае, потому что интерфейс org.slf4j.Logger не, помеченный как java.io.Serializable. Тем не менее, реализация логгеров SLF4J, которые поставляются с SLF4J, все поддерживают сериализацию из коробки. Попробуй. Вы увидите, что он работает.

Вот выдержка из часто задаваемых вопросов SLF4j:

В отличие от статических переменных, экземпляр переменные сериализуются по умолчанию. Начиная с версии 1.5.3 SLF4J, регистратор экземпляры выживают после сериализации. Таким образом, сериализация класса хоста no дольше требует каких-либо специальных действий, даже когда регистраторы объявлены как переменные экземпляра. В предыдущем версии, экземпляры регистратора, необходимые для быть объявленным переходным в хосте класс.

См. также http://slf4j.org/faq.html#declared_static

Ответ 4

Моя первоначальная реакция заключается в том, чтобы задаться вопросом, имеет ли смысл сериализовать экземпляр Logger в вашем объекте. Когда вы deserialize это позже, действительно ли это справедливо ожидать, что среда Logger будет правильной? Я думаю, что я предпочел бы просто пойти с этим и назвать его днем:

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