java - databind - ¿Cómo reutilizo correctamente el ObjectMapper de Jackson?
java jackson annotations (4)
Estoy satisfecho con el funcionamiento de ObjectMapper y el uso general de mi aplicación. Lo que me gustaría entender es la mejor manera de implementar ObjectMapper para garantizar que se vuelva a utilizar y no estoy creando instancias innecesarias dentro de mi aplicación.
Mi opinión es que puedo declarar el ObjectMapper en una clase de Utils de la siguiente manera:
public class Utils {
public final static ObjectMapper mapper = new ObjectMapper();
}
Podría hacer referencia a esto desde los diversos lugares que necesito usando un código como:
JsonSimple jsonSimple = Utils.mapper.readValue(jsonString, JsonSimple.class);
Me encontré con esta otra pregunta ( ¿Debo declarar el ObjectMapper de Jackson como un campo estático? ) Que provocó mi enfoque. Creo que tal vez la diferencia clave es que quiero compartir mi instancia de ObjectMapper en muchas clases diferentes, no solo en una sola clase.
¿Este enfoque suena apropiado o me falta algo?
Gracias
El singleton estático simple que propusiste en tu pregunta es correcto. Un enfoque alternativo sería utilizar el patrón de singleton ( el uso del patrón de singleton se discutió ampliamente en los comentarios de respuesta a una pregunta similar ). Aquí hay un ejemplo simple:
public enum Mapper {
INSTANCE;
private final ObjectMapper mapper = new ObjectMapper();
private Mapper(){
// Perform any configuration on the ObjectMapper here.
}
public ObjectMapper getObjectMapper() {
return mapper;
}
}
Luego puede usar (y reutilizar) el singleton ObjectMapper
siguiente manera:
ObjectMapper mapper = Mapper.INSTANCE.getObjectMapper();
JsonSimple jsonSimple = mapper.readValue(jsonString, JsonSimple.class);
Esto es seguro ya que ObjectMapper
es seguro para subprocesos después de la configuración .
Advertencia: como señala @StaxMan en los comentarios de respuesta, esto NO garantiza contra una (re) configuración adicional en el singleton devuelto.
Está bien usar una única instancia por aplicación, siempre que no llame a ningún método de configuración después de que se haya hecho visible, es decir, debe hacer toda su inicialización dentro de un bloque estático.
Tal como se publicó en otras respuestas, ObjectMapper es realmente Thread safe. Pero reutilizar el mismo objeto puede disminuir el rendimiento de la aplicación, ya que todos los subprocesos 1 se pueden bloquear en un momento determinado a la espera de que el propietario del bloqueo complete la serialización / deserialización de JSON.
Esto es especialmente crítico en servidores web como Jetty o Tomcat: el rendimiento general de todo el servidor puede verse comprometido, por ejemplo, si usa ObjectMapper como punto de entrada / salida de los servicios REST, dependiendo, por supuesto, de su acceso carga.
Entonces, mi sugerencia es usar un grupo de ObjectMappers, para permitir que varios Threads lo usen, y de una manera que no tenga que volver a crear los mappers cada vez que los necesite. El número de ObjectMappers en el grupo debe ser el mismo número de subprocesos de trabajo de su aplicación.
Más sobre: http://jackson-users.ning.com/forum/topics/pooling-objectmapper-for-performance
- EDITAR -
De acuerdo, algunos usuarios son realmente apasionados por la versión de Jackson hasta el punto de que rechazaron esta respuesta sin siquiera mirar el sitio web vinculado. De todos modos, esta respuesta se basa en mi experiencia con la lib sin modificaciones (solo uso de ObjectMapper, sin clases adicionales, sin serializador personalizado, sin JSONFactory personalizado, nada) en el momento de la respuesta (2013). Ya no lo uso en mis proyectos, así que no conozco las versiones más nuevas, pero creo que ya debería estar resuelto.
Como desarrollador, si va a utilizar Jackson o cualquier otro lector / escritor JSON en su proyecto, directa o indirectamente, considere ejecutar una herramienta de creación de perfiles en su servidor para ver cómo se comportan los subprocesos en alta carga. Es un paso simple que no daña.
Utilice la última versión de Jackson y use ObjectReader
y ObjectWriter
lugar de ObjectMapper