2011-05-18 16 views
14

Uso la operación JAXBContext.newInstance en mi aplicación web basada en JBoss. Esta operación, según tengo entendido, es muy pesada. Solo necesito dos instancias únicas de la clase Marshaller.¿Cómo puedo mejorar el rendimiento de la aplicación que utiliza la operación JAXBContext.newInstance?

Mi propuesta inicial es tener un bloque inicializador estático que inicializar estos dos casos sólo una vez en la carga de clases:

public class MyWebApp { 
    private static Marshaller requestMarshaller; 
    private static Marshaller responseMarshaller; 

    static { 
     try { 
      // one time instance creation 
      requestMarshaller = JAXBContext.newInstance(Request.class).createMarshaller(); 
      responseMarshaller = JAXBContext.newInstance(Response.class).createMarshaller(); 
     } catch (JAXBException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void doSomething() { 
      requestMarshaller.marshall(...); 
      responseMarshaller.marshall(...); 
      ... 
    } 

} 

Si esta es una solución razonable, entonces yo supongo que he respondido a mi propia pregunta, pero me gustaría saber si esta es la forma correcta de hacer esto?

Respuesta

24

aplicación Un JAXB (Metro, EclipseLink MOXy, Apache JaxMe, etc) normalmente inicializa sus metadatos durante la llamada JAXBContext.newInstance. Todas las herramientas de OXM deben inicializar los metadatos de asignación en algún punto e intentar minimizar el costo de esta operación. Como es imposible hacerlo sin costo, lo mejor es hacerlo solo una vez. Las instancias de JAXBContext son seguras para hilos, así que sí, solo necesitas crearlas una vez.

Desde el JAXB 2.2 Especificación, sección 4.2 JAXB Contexto:

para evitar la sobrecarga implicada en la creación de una instancia de JAXBContext, una aplicación de JAXB se anima a reutilizar una instancia JAXBContext. Se requiere una implementación de la clase abstracta JAXBContext para ser thread-safe, así, múltiples hilos en una aplicación puede compartir la misma instancia de JAXBContext .

Las instancias de Marshaller y Unmarshaller no son seguras para subprocesos y no deben compartirse entre subprocesos, son livianas de crear.

4

Recientemente realicé algunas pruebas de rendimiento con JAXBContext.newInstance y el resultado está documentado aquí.

http://app-inf.blogspot.com/2012/10/performance-tuning-logging-right-way.html

Cuando llama por un hilo, utilizando un esquema con bastante grande ~ 195 clases generadas, se tomaron ~ 400 ms para terminar. Cuando fue llamado por 20 hilos simultáneamente, causó conflictos de CPU, y tomó hasta ~ 5000ms para finalizar. La creación de Marshaller y la serialización de objetos de un objeto pequeño solo también ~ 14ms.

6

JAXBContext siempre debe ser estático, es seguro para subprocesos.

Marshallers y Unmarshallers son baratos y no son seguros para subprocesos. Debe crear una vez JAXBContext y crear señaleros/unmarshallers para cada operación

public class MyWebApp { 
    private static JAXBContext jaxbContext; 

    static { 
     try { 
      // one time instance creation 
      jaxbContext = JAXBContext.newInstance(Request.class, Response.class); 
     } catch (JAXBException e) { 
      throw new IllegalStateException(e); 
     } 
    } 

    private void doSomething() {     
      jaxbContext.createMarshaller().marshall(...); 
      ... 
    } 

} 

Uso mismo contador de referencias a todo Marshall (añadir todas las clases cuando se crea el contexto).

+2

Solo un comentario: No debe volver a utilizar marshallers/unmarshallers, no son seguros para subprocesos. Simplemente créelos cada vez, es muy rápido – cocorossello

+2

Creo que la solución sugerida aquí es inmediata, y muy útil, pero no creo que el ejemplo del código esté ilustrando el punto hecho en el texto de que no deberías estar llamando a JAXBContext .newInstance() cada vez que necesita un Marshaller. ¿No debería la línea en doSomething() ser 'requestMarshaller = jaxbContext.createMarshaller();'? – rscarter

0

Se puede usar javax.xml.bind.JAXB. Tiene métodos de mariscal directo y no marginales. Por lo tanto, no tiene que preocuparse por la creación de instancia de JAXB.

p. Ej. JAXB.unmarshal (inputStream/inputFile, outputClassExpected) o JAXB.mariscal (jaxbObject, xmlOutputFile/xmlOutputStream)

+0

¿Viste esto en el javadoc de la clase [javax.xml.bind.JAXB] (https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXB.html)? * En términos generales, el rendimiento no es necesariamente óptimo. Se espera que las personas que necesiten escribir código de rendimiento crítico usen el resto de la API JAXB directamente. * –

+0

@ThomasFritsch, sí. El rendimiento puede ser una preocupación para proyectos críticos. Esto debe verificarse si es el caso. Puede estar escribiendo el propio marshaller/un-marshaller que ayudará. –

Cuestiones relacionadas