2010-10-11 20 views

Respuesta

346

Sí, es seguro y recomendable.

La única advertencia de la página que ha recomendado es que no puede modificar la configuración del asignador una vez que se ha compartido; pero no estás cambiando la configuración, así que está bien. Si necesitas cambiar la configuración, lo harías desde el bloque estático y también estaría bien.

EDITAR: (2013/10)

Con 2,0 y por encima, por encima se puede aumentar por señalar que hay una manera aún mejor: utilizar ObjectWriter y ObjectReader objetos, que puede ser construido por ObjectMapper. Son totalmente inmutables, seguros para subprocesos, lo que significa que ni siquiera es teóricamente posible provocar problemas de seguridad de subprocesos (que pueden ocurrir con ObjectMapper si el código intenta reconfigurar la instancia).

+0

¿Tiene alguna fuente de referencia? –

+51

Opps. Me doy cuenta de que eres el desarrollador de Jackson. Gracias por el excelente software! Lo comparo contra JSONObject y gjson, y descubrí que Jackson satisface mis necesidades. –

+8

Oye, no hay problema - me alegra oír esto – StaxMan

3

Aunque es seguro declarar un ObjectMapper estático en términos de seguridad de subprocesos, debe tener en cuenta que la construcción de variables de Objeto estáticas en Java se considera una mala práctica. Para obtener más información, consulte Why are static variables considered evil? (y, si lo desea, my answer)

En resumen, debe evitar las estáticas porque dificultan la realización de pruebas unitarias concisas. Por ejemplo, con un ObjectMapper estático final, no puede cambiar la serialización de JSON por un código ficticio o un no-op.

Además, un final estático le impide volver a configurar ObjectMapper en tiempo de ejecución. Puede que no visualice una razón para eso ahora, pero si se bloquea en un patrón final estático, nada menos que derribar el cargador de clases le permitirá volver a inicializarlo.

En el caso de ObjectMapper está bien, pero en general es una mala práctica y no hay ninguna ventaja sobre el uso de un patrón singleton o inversión de control para administrar sus objetos de larga vida.

+18

Sugeriría que aunque los singletons STATEFUL estáticos son típicamente un signo de peligro, existen motivos suficientes por los que en este caso, compartir un solo (o, pequeño) número de instancias tiene sentido. Uno puede desear usar la Inyección de Dependencia para eso; pero al mismo tiempo vale la pena preguntar si hay un problema real o potencial para resolver. Esto se aplica especialmente a las pruebas: el hecho de que algo pueda ser problemático en algún caso no significa que sea para su uso. Entonces: ser consciente de los problemas, genial. Suponiendo que "una talla para todos", no tan buena. – StaxMan

+3

Obviamente, es importante comprender los problemas relacionados con cualquier decisión de diseño, y si puede hacer algo sin causar problemas para su caso de uso, por definición, no causará ningún problema. Sin embargo, argumentaría que no hay beneficios para el uso de instancias estáticas y abre la puerta a problemas significativos en el futuro a medida que su código evoluciona o se transfiere a otros desarrolladores que podrían no entender sus decisiones de diseño. Si su marco soporta alternativas, no hay razón para no evitar instancias estáticas, ciertamente no hay ventajas para ellos. – JBCP

+7

Creo que esta discusión se dirige a tangentes muy generales y menos útiles. No tengo ningún problema para sugerir que es bueno sospechar de singletons estáticos. Simplemente estoy familiarizado con el uso de este caso en particular y no creo que uno pueda llegar a conclusiones específicas a partir del conjunto de pautas generales. Así que lo dejo así. – StaxMan

22

Aunque ObjectMapper es seguro para subprocesos, desaconsejaría declararlo como una variable estática, especialmente en una aplicación multiproceso. Ni siquiera porque sea una mala práctica, sino porque corre un alto riesgo de bloqueo. Lo estoy contando desde mi propia experiencia. Creé una aplicación con 4 hilos idénticos que obtenían y procesaban datos JSON de los servicios web. Mi solicitud fue estancando con frecuencia en el siguiente orden, de acuerdo con el volcado de hilo:

Map aPage = mapper.readValue(reader, Map.class); 

Además de eso, el rendimiento no era bueno. Cuando reemplacé la variable estática con la variable basada en la instancia, el estancamiento desapareció y el rendimiento se cuadruplicó. Es decir. 2.4 millones de documentos JSON fueron procesados ​​en 40min.56sec., En lugar de 2.5 horas antes.

+8

La respuesta de Gary tiene sentido por completo. Pero ir con la creación de una instancia 'ObjectMapper' para cada instancia de clase puede evitar bloqueos, pero puede ser muy pesada en GC más adelante (imagine una instancia de ObjectMapper para cada instancia de la clase que cree). Un enfoque de ruta intermedia puede ser, en lugar de mantener solo una instancia estática (pública) de 'ObjectMapper' en la aplicación, puede declarar una instancia (privada) ** estática ** de' ObjectMapper' ** en cada clase **. Esto reducirá un bloqueo global (distribuyendo la carga en la clase), y tampoco creará ningún objeto nuevo, por lo tanto, también se encenderá en el GC. – Abhidemon

+0

Y, por supuesto, mantener un 'ObjectPool' es la mejor forma de hacerlo, dando así las mejores prestaciones de' GC' y 'Lock'. Puede consultar el siguiente enlace para la implementación 'ObjectPool' de apache-common. https://commons.apache.org/proper/commons-pool/api-1.6/org/apache/commons/pool/impl/GenericObjectPool.html – Abhidemon

+5

Sugeriría una alternativa: mantener estático 'ObjectMapper' en alguna parte, pero solo obtener instancias de 'ObjectReader' /' ObjectWriter' (a través de métodos auxiliares), retener las referencias a las de otros lugares (o llamar dinámicamente). Estos objetos lectoras/grabadoras no solo son totalmente reconfigurables con thrt, sino también muy ligeras (instancias wrt mapper). Por lo tanto, mantener miles de referencias no agrega mucho uso de memoria. – StaxMan

-1

com.fasterxml.jackson.databind.type.TypeFactory._hashMapSuperInterfaceChain (HierarchicType)

com.fasterxml.jackson.databind.type.TypeFactory._findSuperInterfaceChain(Type, Class) 
    com.fasterxml.jackson.databind.type.TypeFactory._findSuperTypeChain(Class, Class) 
    com.fasterxml.jackson.databind.type.TypeFactory.findTypeParameters(Class, Class, TypeBindings) 
     com.fasterxml.jackson.databind.type.TypeFactory.findTypeParameters(JavaType, Class) 
      com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(ParameterizedType, TypeBindings) 
       com.fasterxml.jackson.databind.type.TypeFactory._constructType(Type, TypeBindings) 
       com.fasterxml.jackson.databind.type.TypeFactory.constructType(TypeReference) 
        com.fasterxml.jackson.databind.ObjectMapper.convertValue(Object, TypeReference) 

El _hashMapSuperInterfaceChain método en la clase com.fasterxml.jackson.databind.type.TypeFactory está sincronizado. Estoy viendo contención en el mismo a altas cargas.

Puede ser otra razón para evitar un ObjectMapper estático

+0

Asegúrese de revisar las últimas versiones (y tal vez indicar la versión que usa aquí). Se han realizado mejoras en el bloqueo basadas en problemas informados, y la resolución de tipo (f.ex) se reescribió completamente para Jackson 2.7. Aunque en este caso, 'TypeReference' es algo caro de usar: si es posible, resolverlo con' JavaType' evitaría bastante procesamiento ('TypeReference's no puede, por desgracia, almacenarse en caché por razones que No profundizaré aquí), ya que están "totalmente resueltos" (supertipo, tipificación genérica, etc.). – StaxMan

Cuestiones relacionadas