2008-09-17 8 views
27

Я использую Java 1.4 с Log4J.Должен ли логгер Log4J быть объявлен переходным?

Некоторые из моих кодов включают в себя объекты сериализации и десериализации значений (POJO).

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

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

сериализатора жалуется на org.apache.log4j.Logger не является Serializable.

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

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

вместо этого?

+1

Несколько вопросов, которые вы могли бы задать себе и добавить как отредактировать свой вопрос. Какова ваша мысль и против ее преемственности? Что означает переходный период? – svrist

+1

Я должен был упомянуть, мне нравится идея иметь регистратор для каждого экземпляра, а не один для каждого класса. У меня было бы много экземпляров одного и того же класса, созданных и управляемых контейнером (скажем, контекст приложения Spring) и хотелось бы переключать уровни ведения журнала на основе каждого компонента, а не на основе каждого класса. В примере контекста приложения Spring регистратор будет объявлен как что-то вроде приватный конечный переходный процесс Logger log = Logger.getLogger (getBeanName()); где боб больше не POJO и реализует BeanNameAware – Vihung

+1

См. Также [FAQ SLF4J] (http://www.slf4j.org/faq.html#declared_static): * «Должны ли члены класса Logger объявлять как static ... [...] Таким образом, объявление членов журнала в качестве статических переменных требует меньшего времени процессора и имеет немного меньший объем памяти. [...] Однако переменные экземпляра позволяют создавать отдельную среду регистрации для каждого приложения, даже для журналов, объявленных в разделяемых библиотеках. Возможно, что более важно, чем ранее упомянутые соображения, переменные экземпляра IOC-friendly, тогда как статические переменные - нет ». * – Arjan

ответ

26

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

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

+2

Статические регистраторы не подходят для повторного развертывания веб-приложений. –

+0

@ ThorbjørnRavnAndersen Не могли бы вы объяснить, почему это плохо для перераспределения веб-приложений? Или эта проблема исправлена ​​с новыми AS, такими как WildFly 8.2 и т. Д.? – CSchulz

+5

Статические логгеристы имеют тенденцию - если ваше приложение не очень тщательно закодировано - держаться за классные загрузчики, чтобы они не могли собирать мусор. Это показано, например, неуклонно увеличивая использование памяти во время сборки maven, которые исчезают, когда javac разветвляется maven. –

11

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

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

+4

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

+9

* «Нет причин, чтобы сделать журнал нестационарным, если у вас нет веских причин сделать это». * - это заставляет мою голову взорваться! ;-) – Arjan

2

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

0

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

0

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

2

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

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

5

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

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

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

9

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

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

В JavaDocs для Serializable имеет информацию об этом методе.

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

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

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

0

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^