Log4J记录器应该声明为瞬态吗?

Vih*_*ung 30 java logging serialization log4j

我正在使用Java 1.4和Log4J.

我的一些代码涉及序列化和反序列化值对象(PO​​JO).

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

private final Logger log = Logger.getLogger(getClass());
Run Code Online (Sandbox Code Playgroud)

序列化程序抱怨org.apache.log4j.Logger不是Serializable.

我应该用吗?

private final transient Logger log = Logger.getLogger(getClass());
Run Code Online (Sandbox Code Playgroud)

代替?

Ale*_*aho 26

如何使用静态记录器?或者您是否需要为每个类的实例提供不同的记录器参考?默认情况下,静态字段未序列化; 您可以使用ObjectStreamFieldnamed 的私有静态最终数组显式声明要序列化的字段serialPersistentFields.请参阅Oracle文档

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

  • 静态记录器倾向于 - 除非你的应用程序被非常仔细地编码 - 保持类加载器,以便它们不能被垃圾收集.这显示了例如在maven构建期间稳定增加的内存使用量,当javac由maven分叉时消失. (5认同)
  • 静态记录器不适合重新部署Web应用程序. (2认同)

min*_*das 11

记录器必须是静态的; 这会使它不可序列化.

除非你有充分的理由这样做,否则没有理由让logger成为非静态的.

  • *"没有理由让记录器非静态,除非你有充分的理由这样做."* - 这让我的头爆炸了!;-) (10认同)
  • 如果要为每个实例使用不同的记录器名称(例如,在记录器名称的末尾附加实例唯一字符串),或者如果在超类对象中有记录器,则有时可以使用非静态记录器.并且您希望它使用子类实例的名称. (5认同)

Joh*_*her 9

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

 private void readObject(java.io.ObjectInputStream in) 
   throws IOException, ClassNotFoundException;
Run Code Online (Sandbox Code Playgroud)

Serializable的javadoc 有关于此方法的信息.

您的实现将类似于:

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

如果不这样做,则在反序列化对象后,log将为null.


use*_*189 5

将记录器字段声明为静态或瞬态.

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

通常记录器字段被声明为静态,但是如果您需要它是一个实例字段,则只需将其声明为瞬态,因为它通常用于任何非可序列化字段.在反序列化时,logger字段将为null,因此您必须实现readObject()方法以正确初始化它.