2008-09-17 10 views
27

Estoy usando Java 1.4 con Log4J.¿Debería declararse un registrador Log4J como transitorio?

Parte de mi código implica serializar y deserializar objetos de valor (POJO).

Cada uno de mis POJOs declara un registrador con

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

El serializador se queja de org.apache.log4j.Logger no ser Serializable.

¿Debo usar

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

en su lugar?

+1

Un par de preguntas que podría hacerse y agregar como edición a su pregunta. ¿Cuál es su pensamiento a favor y en contra de hacerlo transitorio? ¿Qué significa transitorio? – svrist

+1

Debería haber mencionado, me gusta la idea de tener un registrador para cada instancia en lugar de uno para cada clase. Tendría muchas instancias de la misma clase creadas y creadas por un contenedor (digamos un contexto de la aplicación Spring) y me gustaría cambiar los niveles de registro en base a cada poroto en lugar de por clase. En el ejemplo de un contexto de aplicación Spring, el registrador se declararía como algo similar a log transitorio final privado Logger = Logger.getLogger (getBeanName()); donde el bean ya no es un POJO e implementa BeanNameAware – Vihung

+1

Ver también [las preguntas frecuentes de SLF4J] (http://www.slf4j.org/faq.html#declared_static): * "Deberían declararse los miembros de Logger de una clase como static? [...] En resumen, declarar a los miembros del registrador como variables estáticas requiere menos tiempo de CPU y una memoria ligeramente más pequeña. [...] Sin embargo, las variables de instancia hacen posible crear un entorno de registrador distinto para cada aplicación, incluso para los registradores declarados en bibliotecas compartidas. Tal vez más importantes que las consideraciones mencionadas anteriormente, las variables de instancia son IOC-friendly mientras que las variables estáticas no lo son. "* – Arjan

Respuesta

26

¿Qué tal el uso de un registrador estático? ¿O necesita una referencia de registrador diferente para cada instancia de la clase? Los campos estáticos no están serializados de manera predeterminada; puede declarar explícitamente campos para serializar con una matriz privada, estática y final de ObjectStreamField llamada serialPersistentFields. See Oracle documentation

Contenido adicional: Al usar getLogger(getClass()), usará el mismo registrador en cada instancia. Si desea usar un registrador separado para cada instancia, debe diferenciar el nombre del registrador en el método getLogger(). p.ej. getLogger (getClass(). getName() + hashCode()). Luego debe usar el atributo transitorio para asegurarse de que el registrador no esté serializado.

+2

Los registradores estáticos no son buenos para la redistribución de aplicaciones web. –

+0

@ ThorbjørnRavnAndersen ¿Puedes explicar por qué no es bueno para redesplegar aplicaciones web? ¿O es este problema el más nuevo AS como WildFly 8.2 y así sucesivamente? Los registradores estáticos – CSchulz

+5

tienen una tendencia a, a menos que su aplicación esté cuidadosamente codificada, a aferrarse a los cargadores de clase para que no puedan ser recolectados. Esto se muestra en, p. Aumento constante del uso de la memoria durante las compilaciones maven que desaparecen cuando maven encierra el javac. –

11

El registrador debe ser estático; esto lo haría no serializable.

No hay razón para hacer que el registrador no sea estático, a menos que tenga una razón sólida para hacerlo.

+4

A veces puede ser útil tener un registrador no estático si desea usar diferentes nombres de registradores para cada instancia (p.ejanexando una cadena de instancia única al final del nombre del registrador), o si tiene un registrador en un objeto de superclase y desea que use el nombre de la instancia de la subclase. –

+9

* "No hay ninguna razón para hacer que el registrador no sea estático, a menos que tenga una razón sólida para hacerlo". * - ¡Esto hace que mi cabeza explote! ;-) – Arjan

2

Pruebe a hacer el registrador estático en su lugar. Entonces, no tiene que preocuparse por la serialización porque la maneja el cargador de clases.

0

Si quiere que el registrador sea por instancia, entonces sí, querrá hacerlo transitorio si va a serializar sus objetos. Log4J Loggers no son serializables, no en la versión de Log4J que estoy usando de todos modos, así que si no haces que tus campos Logger sean transitorios obtendrás excepciones en la serialización.

0

Los registradores no son serializables, por lo que debe usar transitorios cuando los almacene en campos de instancia. Si desea restaurar el registrador después de la deserialización, puede almacenar el Nivel (Cadena) indide su objeto que se serializa.

2

Este tipo de casos, particularmente en EJB, generalmente se manejan mejor a través del estado local de subprocesos. Por lo general, el caso de uso es algo así como que tiene una transacción particular que tiene un problema y necesita elevar el registro para depurar esa operación, de modo que pueda generar un registro detallado de la operación problemática. Lleve un estado local de subprocesos en la transacción y utilícelo para seleccionar el registrador correcto. Francamente, no sé dónde sería beneficioso establecer el nivel en una INSTANCIA en este entorno porque el mapeo de instancias en la transacción debe ser una función de nivel de contenedor, no tendrá control de qué instancia se utiliza en un transacción dada de todos modos.

Incluso en los casos en los que se trata de una DTO, generalmente no es una buena idea diseñar su sistema de tal forma que se requiera una instancia específica dado porque el diseño puede evolucionar fácilmente de manera que lo convierta en un mal elección. Podrías venir dentro de un mes y decidir que las consideraciones de eficiencia (almacenamiento en caché u otra optimización de cambio de ciclo de vida) romperán tu suposición sobre el mapeo de instancias en unidades de trabajo.

5

O declare su campo de registrador como estático o transitorio.

Ambas formas garantizan que el método writeObject() no intente escribir el campo en la secuencia de salida durante la serialización.

Por lo general, los campos del registrador se declaran estáticos, pero si necesita que sea un campo de instancia, simplemente se declara transitorio, como suele hacerse para cualquier campo no serializable. Tras la deserialización, el campo de registro será nulo, por lo que debe implementar un método readObject() para inicializarlo correctamente.

9

Si realmente quiere ir al enfoque transitorio, tendrá que restablecer el registro cuando se deserialice su objeto. La manera de hacerlo es poner en práctica el método:

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

Los javadocs para Serializable tiene información sobre este método.

Su puesta en práctica de la misma se verá algo como:

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

Si no hace esto, entonces la sesión será nulo después de deserializar el objeto.

0

Existen buenas razones para usar un registrador de instancias. Un muy buen caso de uso es para que pueda declarar el registrador en una superclase y usarlo en todas las subclases (el único inconveniente es que los registros de la superclase se atribuyen a la subclase, pero generalmente es fácil mira eso).

(Como otros han mencionado usar estático o transitorio).

Cuestiones relacionadas