Должен ли регистратор Log4J быть объявлен как временный?

StackOverflow https://stackoverflow.com/questions/82109

Вопрос

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

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

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

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

Сериализатор жалуется на то, что org.apache.log4j.Регистратор не является сериализуемым.

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

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

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

 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();
 }

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

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

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

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

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

Такого рода случаи, особенно в EJB, как правило, лучше всего обрабатываются через локальное состояние потока.Обычно вариант использования выглядит примерно так: у вас есть конкретная транзакция, которая сталкивается с проблемой, и вам нужно повысить уровень ведения журнала до уровня отладки для этой операции, чтобы вы могли сгенерировать подробное ведение журнала для проблемной операции.Перенесите некоторое локальное состояние потока в транзакцию и используйте это для выбора правильного регистратора.Честно говоря, я не знаю, где было бы полезно установить уровень для ЭКЗЕМПЛЯРА в этой среде, потому что отображение экземпляров в транзакцию должно быть функцией уровня контейнера, вы фактически не будете контролировать, какой экземпляр используется в данной транзакции в любом случае.

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

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

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

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

(Как упоминали другие, используйте static или transient).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top