Должен ли регистратор Log4J быть объявлен временным? - PullRequest
30 голосов
/ 17 сентября 2008

Я использую Java 1.4 с Log4J.

Часть моего кода включает сериализацию и десериализацию объектов-значений (POJO).

Каждый из моих POJO объявляет регистратор с

private final Logger log = Logger.getLogger(getClass());

Сериализатор жалуется на то, что org.apache.log4j.Logger не поддерживает сериализацию.

Должен ли я использовать

private final transient Logger log = Logger.getLogger(getClass());

вместо

Ответы [ 9 ]

26 голосов
/ 17 сентября 2008

Как насчет использования статического регистратора? Или вам нужна отдельная ссылка на регистратор для каждого экземпляра класса? Статические поля не сериализуются по умолчанию; Вы можете явно объявить поля для сериализации с частным, статическим, окончательным массивом ObjectStreamField с именем serialPersistentFields. См. Документацию Oracle

Добавлен контент: Поскольку вы используете getLogger (getClass ()) , вы будете использовать один и тот же регистратор в каждом случае. Если вы хотите использовать отдельный регистратор для каждого экземпляра, вы должны различать имя регистратора в методе getLogger (). например getLogger (getClass (). getName () + hashCode ()). Затем вы должны использовать переходный атрибут, чтобы убедиться, что регистратор не сериализован.

11 голосов
/ 17 сентября 2008

Регистратор должен быть статическим; это сделало бы его не сериализуемым.

Нет причин делать регистратор нестатичным, если только у вас нет веских причин для этого.

9 голосов
/ 17 сентября 2008

Если вы действительно хотите использовать переходный подход, вам нужно будет сбросить журнал, когда ваш объект десериализован. Способ сделать это состоит в том, чтобы реализовать метод:

 private void readObject(java.io.ObjectInputStream in) 
   throws IOException, ClassNotFoundException;

Javadocs для Сериализуемый содержит информацию об этом методе.

Ваша реализация будет выглядеть примерно так:

 private void readObject(java.io.ObjectInputStream in) 
     throws IOException, ClassNotFoundException {
   log = Logger.getLogger(...);
   in.defaultReadObject();
 }

Если вы этого не сделаете, журнал будет нулевым после десериализации вашего объекта.

5 голосов
/ 17 сентября 2008

Либо объявите поле логгера как статическое, либо как временное.

Оба способа гарантируют, что метод writeObject () не будет пытаться записать поле в выходной поток во время сериализации.

Обычно поля регистратора объявляются статическими, но если вам нужно, чтобы это было поле экземпляра, просто объявите его как переходный, как это обычно делается для любого несериализуемого поля. Однако после десериализации поле логгера будет нулевым, поэтому вам нужно реализовать метод readObject () для его правильной инициализации.

2 голосов
/ 17 сентября 2008

Такие случаи, особенно в EJB, обычно лучше всего обрабатывать через локальное состояние потока. Обычно сценарий использования похож на то, как если бы у вас была определенная транзакция, в которой возникла проблема, и вам необходимо повысить уровень ведения журнала, чтобы отладить эту операцию, чтобы вы могли сгенерировать подробный журнал операции, в которой возникла проблема. Перенести в транзакцию локальное состояние потока и использовать его для выбора правильного регистратора. Честно говоря, я не знаю, где было бы полезно установить уровень INSTANCE в этой среде, потому что отображение экземпляров в транзакции должно быть функцией уровня контейнера, на самом деле вы не сможете контролировать, какой экземпляр используется в данная транзакция в любом случае.

Даже в тех случаях, когда вы имеете дело с DTO, обычно не стоит проектировать вашу систему таким образом, чтобы требовался конкретный экземпляр, потому что дизайн может легко эволюционировать таким образом, что это станет плохим выбором. , Вы можете прийти через месяц и решить, что соображения эффективности (кэширование или какая-либо другая оптимизация с изменением жизненного цикла) нарушат ваше предположение о сопоставлении экземпляров в единицах работы.

2 голосов
/ 17 сентября 2008

Попробуйте вместо этого сделать Logger статическим. Чем вам не нужно заботиться о сериализации, потому что она обрабатывается загрузчиком классов.

0 голосов
/ 17 сентября 2008

Есть веские причины использовать регистратор экземпляров. Один очень хороший вариант использования: вы можете объявить регистратор в суперклассе и использовать его во всех подклассах (единственный недостаток заключается в том, что журналы суперкласса относятся к подклассу, но обычно легко увидеть это).

(Как и другие упоминали использовать статический или переходный процесс).

0 голосов
/ 17 сентября 2008

Регистраторы не сериализуемы, поэтому вы должны использовать переходные процессы при хранении их в полях экземпляра. Если вы хотите восстановить регистратор после десериализации, вы можете сохранить уровень (строку) внутри вашего объекта, который сериализуется.

0 голосов
/ 17 сентября 2008

Если вы хотите, чтобы Logger был для каждого экземпляра, тогда да, вы бы хотели сделать его временным, если вы собираетесь сериализовать свои объекты. Log4J Регистраторы не сериализуются, не в той версии Log4J, которую я использую в любом случае, поэтому, если вы не сделаете свои поля Logger временными, вы получите исключения при сериализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...