java 是否应该将 Log4J 记录器声明为瞬态?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/82109/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:58:48  来源:igfitidea点击:

Should a Log4J logger be declared as transient?

javaloggingserializationlog4j

提问by Vihung

I am using Java 1.4 with Log4J.

我在 Log4J 中使用 Java 1.4。

Some of my code involves serializing and deserializing value objects (POJOs).

我的一些代码涉及序列化和反序列化值对象 (POJO)。

Each of my POJOs declares a logger with

我的每个 POJO 都声明了一个记录器

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

The serializer complains of org.apache.log4j.Logger not being Serializable.

序列化程序抱怨 org.apache.log4j.Logger 不能序列化。

Should I use

我应该使用

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

instead?

反而?

采纳答案by Aleksi Yrttiaho

How about using a static logger? Or do you need a different logger reference for each instance of the class? Static fields are not serialized by default; you can explicitly declare fields to serialize with a private, static, final array of ObjectStreamFieldnamed serialPersistentFields. See Oracle documentation

使用静态记录器怎么样?或者您是否需要为类的每个实例使用不同的记录器引用?静态字段默认不序列化;您可以显式声明字段以使用ObjectStreamField命名的私有、静态、最终数组进行序列化serialPersistentFields请参阅 Oracle 文档

Added content: As you use getLogger(getClass()), you will use the same logger in each instance. If you want to use separate logger for each instance you have to differentiate on the name of the logger in the getLogger() -method. e.g. getLogger(getClass().getName() + hashCode()). You should then use the transient attribute to make sure that the logger is not serialized.

添加的内容:当您使用getLogger(getClass()) 时,您将在每个实例中使用相同的记录器。如果您想为每个实例使用单独的记录器,您必须在 getLogger() 方法中区分记录器的名称。例如 getLogger(getClass().getName() + hashCode())。然后您应该使用瞬态属性来确保记录器没有被序列化。

回答by mindas

The logger must be static; this would make it non-serializable.

记录器必须是静态的;这将使其不可序列化。

There's no reason to make logger non-static, unless you have a strong reason to do it so.

没有理由使记录器非静态,除非您有充分的理由这样做。

回答by John Meagher

If you reallywant to go the transient approach you will need to reset the log when your object is deserialized. The way to do that is to implement the method:

如果您真的想采用瞬态方法,则需要在反序列化对象时重置日志。这样做的方法是实现该方法:

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

The javadocs for Serializablehas information on this method.

Serializable的 javadocs有关于这个方法的信息。

Your implementation of it will look something like:

您对它的实现将类似于:

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

If you do not do this then log will be null after deserializing your object.

如果不这样做,则反序列化对象后日志将为空。

回答by user9189

Either declare your logger field as static or as transient.

将您的记录器字段声明为静态或瞬态。

Both ways ensure the writeObject() method will not attempt to write the field to the output stream during serialization.

这两种方式都确保 writeObject() 方法在序列化期间不会尝试将字段写入输出流。

Usually logger fields are declared static, but if you need it to be an instance field just declare it transient, as its usually done for any non-serializable field. Upon deserialization the logger field will be null, though, so you have to implement a readObject() method to initialize it properly.

通常记录器字段被声明为静态,但如果你需要它是一个实例字段,只需将它声明为瞬态,就像它通常对任何不可序列化字段所做的那样。但是,在反序列化时,记录器字段将为空,因此您必须实现 readObject() 方法以正确初始化它。

回答by user9189

These kinds of cases, particularly in EJB, are generally best handled via thread local state. Usually the use case is something like you have a particular transaction which is encountering a problem and you need to elevate logging to debug for that operation so you can generate detailed logging on the problem operation. Carry some thread local state across the transaction and use that to select the correct logger. Frankly I don't know where it would be beneficial to set the level on an INSTANCE in this environment because the mapping of instances into the transaction should be a container level function, you won't actually have control of which instance is used in a given transaction anyway.

这些类型的情况,尤其是在 EJB 中,通常最好通过线程本地状态来处理。通常用例类似于您有一个遇到问题的特定事务,您需要提升日志记录以调试该操作,以便您可以生成有关问题操作的详细日志记录。在整个事务中携带一些线程本地状态并使用它来选择正确的记录器。坦率地说,我不知道在这种环境中在 INSTANCE 上设置级别有什么好处,因为实例到事务的映射应该是容器级别的功能,您实际上无法控制在一个实例中使用哪个实例无论如何给定交易。

Even in cases where you're dealing with a DTO it is not generally a good idea to design your system in such a way that a given specific instance is required because the design can easily evolve in ways that make that a bad choice. You could come along a month from now and decide that efficiency considerations (caching or some other life cycle changing optimization) will break your assumption about the mapping of instances into units of work.

即使在处理 DTO 的情况下,以需要给定特定实例的方式设计系统通常也不是一个好主意,因为设计很容易演变成一个糟糕的选择。您可以在一个月后决定效率考虑(缓存或其他一些生命周期更改优化)将打破您关于实例映射到工作单元的假设。

回答by Philip Helger

Try making the Logger static instead. Than you don't have to care about serialization because it is handled by the class loader.

尝试将 Logger 设为静态。你不必关心序列化,因为它是由类加载器处理的。

回答by MB.

If you want the Logger to be per-instance then yes, you would want to make it transient if you're going to serialize your objects. Log4J Loggers aren't serializable, not in the version of Log4J that I'm using anyway, so if you don't make your Logger fields transient you'll get exceptions on serialization.

如果您希望 Logger 是针对每个实例的,那么是的,如果您要序列化您的对象,您可能希望使其成为瞬态。Log4J Logger 是不可序列化的,无论如何在我使用的 Log4J 版本中都不是,所以如果你不让你的 Logger 字段是瞬态的,你会在序列化时遇到异常。

回答by Glever

Loggers are not serializable so you must use transient when storing them in instance fields. If you want to restore the logger after deserialization you can store the Level (String) indide your object which does get serialized.

记录器不可序列化,因此在将它们存储在实例字段中时必须使用瞬态。如果你想在反序列化后恢复记录器,你可以在你的对象中存储级别(字符串),它确实被序列化了。

回答by James A. N. Stauffer

There are good reasons to use an instance logger. One very good use case is so you can declare the logger in a super-class and use it in all sub-classes (the only downside is that logs from the super-class are attributed to the sub-class but it is usually easy to see that).

有充分的理由使用实例记录器。一个非常好的用例是,您可以在超类中声明记录器并在所有子类中使用它(唯一的缺点是来自超类的日志归因于子类,但通常很容易看到那个)。

(Like others have mentioned use static or transient).

(就像其他人提到的使用静态或瞬态一样)。