JAXB creating context and marshallers cost

后端 未结 8 2070
情深已故
情深已故 2020-11-28 02:00

The question is a bit theoretical, what is the cost of creating JAXB context, marshaller and unmarshaller?

I\'ve found that my code could benefit from keeping the sa

相关标签:
8条回答
  • 2020-11-28 02:30

    Creating JAXBContext within a enum and accessing it within application Thread to create Marshaller/Unmarshaller will suffice.

    public enum MyApplicationJAXBContext {
    
        REQ(Request.class), RESP(Response.class);
    
        private final JAXBContext jaxbContext;
    
        MyApplicationJAXBContext(Class contextClass) {
    
            try {
                jaxbContext = JAXBContext.newInstance(contextClass);
            } catch (JAXBException e) 
                throw new RunTimeException(e);
               // Lets caller decide what to do ?
            }
        }
    
        public JAXBContext getJaxbContext() {
            return jaxbContext;
        }
    }
    
    
    public class MyAppCallable implements Callable<Response> {
    
    private final Request req;
    public MyAppCallable(Request req) {
        this.req = req;
    }
    
    
    public Response call() {
    
    Marshaller marshaller = MyApplicationJAXBContext.REQ.getJaxbContext().createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    // Anything else you want to configure properties
    Unmarshaller unmarshaller = MyApplicationJAXBContext.RESP.getJaxbContext().createUnmarshaller();
    
    /** 
    All other logic you want to do after req/rsp usage and return Response
    **/
    
    }
    
    }
    
    0 讨论(0)
  • 2020-11-28 02:34

    Ideally, you should have a singleton JAXBContext and local instances of Marshaller and Unmarshaller.

    JAXBContext instances are thread-safe while Marshaller and Unmarshaller instances are not thread-safe and should never be shared across threads.

    0 讨论(0)
  • 2020-11-28 02:35

    Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

    JAXBContext is thread safe and should only be created once and reused to avoid the cost of initializing the metadata multiple times. Marshaller and Unmarshaller are not thread safe, but are lightweight to create and could be created per operation.

    0 讨论(0)
  • 2020-11-28 02:36

    It's a pity that this isn't specifically described in the javadoc. What I can tell is that Spring uses a global JAXBContext, shared between threads, whereas it creates a new marshaller for each marshalling operation, with a javadoc comment in the code saying that JAXB marshallers are not necessarily thread-safe.

    The same is said on this page:https://javaee.github.io/jaxb-v2/doc/user-guide/ch03.html#other-miscellaneous-topics-performance-and-thread-safety.

    I would guess that creating a JAXBContext is a costly operation, because it involves scanning classes and packages for annotations. But measuring it is the best way to know.

    0 讨论(0)
  • 2020-11-28 02:36

    I usually solve problems like this with a ThreadLocal class pattern. Given the fact that you need a different marshaller for each Class, you can combine it with a singleton-map pattern.

    To save you 15 minutes, of work. Here follows my implementation of a thread-safe Factory for Jaxb Marshallers and Unmarshallers.

    It allows you to access the instances as follows ...

    Marshaller m = Jaxb.get(SomeClass.class).getMarshaller();
    Unmarshaller um = Jaxb.get(SomeClass.class).getUnmarshaller();
    

    And the code you will need is a little Jaxb class that looks as follows:

    public class Jaxb
    {
      // singleton pattern: one instance per class.
      private static Map<Class,Jaxb> singletonMap = new HashMap<>();
      private Class clazz;
    
      // thread-local pattern: one marshaller/unmarshaller instance per thread
      private ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<>();
      private ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<>();
    
      // The static singleton getter needs to be thread-safe too, 
      // so this method is marked as synchronized.
      public static synchronized Jaxb get(Class clazz)
      {
        Jaxb jaxb =  singletonMap.get(clazz);
        if (jaxb == null)
        {
          jaxb = new Jaxb(clazz);
          singletonMap.put(clazz, jaxb);
        }
        return jaxb;
      }
    
      // the constructor needs to be private, 
      // because all instances need to be created with the get method.
      private Jaxb(Class clazz)
      {
         this.clazz = clazz;
      }
    
      /**
       * Gets/Creates a marshaller (thread-safe)
       * @throws JAXBException
       */
      public Marshaller getMarshaller() throws JAXBException
      {
        Marshaller m = marshallerThreadLocal.get();
        if (m == null)
        {
          JAXBContext jc = JAXBContext.newInstance(clazz);
          m = jc.createMarshaller();
          marshallerThreadLocal.set(m);
        }
        return m;
      }
    
      /**
       * Gets/Creates an unmarshaller (thread-safe)
       * @throws JAXBException
       */
      public Unmarshaller getUnmarshaller() throws JAXBException
      {
        Unmarshaller um = unmarshallerThreadLocal.get();
        if (um == null)
        {
          JAXBContext jc = JAXBContext.newInstance(clazz);
          um = jc.createUnmarshaller();
          unmarshallerThreadLocal.set(um);
        }
        return um;
      }
    }
    
    0 讨论(0)
  • 2020-11-28 02:47

    JAXB 2.2 (JSR-222) has this to say, in section "4.2 JAXBContext":

    To avoid the overhead involved in creating a JAXBContext instance, a JAXB application is encouraged to reuse a JAXBContext instance. An implementation of abstract class JAXBContext is required to be thread-safe, thus, multiple threads in an application can share the same JAXBContext instance.

    [..]

    JAXBContext class is designed to be immutable and thus threadsafe. Given the amount of dynamic processing that potentially could take place when creating a new instance of JAXBContxt, it is recommended that a JAXBContext instance be shared across threads and reused as much as possible to improve application performance.

    Unfortunately, the specification does not make any claims regarding thread-safety of Unmarshaller and Marshaller. So it is best to assume they are not.

    0 讨论(0)
提交回复
热议问题