首页 文章

JAXB创建上下文和marshallers成本

提问于
浏览
88

问题有点理论化,创建JAXB上下文,marshaller和unmarshaller的成本是多少?

我发现我的代码可以从保持相同的JAXB上下文和可能与所有编组操作相同的编组器中受益,而不是在每个编组时创建上下文和编组器 .

那么创建JAXB上下文和marshaller / unmarshaller的成本是多少?是否可以为每个编组操作创建上下文编组器,或者最好避免它?

7 回答

  • 2

    Note: 我是EclipseLink JAXB (MOXy)领导,是JAXB 2(JSR-222)专家组的成员 .

    JAXBContext 是线程安全的,只应创建一次并重复使用,以避免多次初始化元数据的成本 . MarshallerUnmarshaller 不是线程安全的,但是要创建轻量级,并且可以按操作创建 .

  • 32

    理想情况下,您应该有一个单独的 JAXBContextMarshallerUnmarshaller 的本地实例 .

    JAXBContext 实例是线程安全的,而 MarshallerUnmarshaller 实例是 not 线程安全的,不应跨线程共享 .

  • 0

    它在javadoc中具体描述了's a pity that this isn' . 我可以告诉你,Spring使用一个全局JAXBContext,在线程之间共享,而它为每个编组操作创建一个新的编组器,代码中的javadoc comment表示JAXB marshallers不一定是线程安全的 .

    本页面的内容也是如此:http://jaxb.java.net/guide/Performance_and_thread_safety.html .

    我猜想创建一个JAXBContext是一项代价高昂的操作,因为它涉及扫描类和注释的包 . 但测量它是最好的方法 .

  • 1

    我使用共享线程安全 JAXBContext 和线程本地 un/marschallers 解决了这个问题(因此理论上,将有与访问它们的线程一样多的 un/marshaller 实例),仅在 un/marshaller 的初始化时进行同步 .

    private final ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<Unmarshaller>() {
        protected synchronized Unmarshaller initialValue() {
            try {
                return jaxbContext.createUnmarshaller();
            } catch (JAXBException e) {
                throw new IllegalStateException("Unable to create unmarshaller");
            }
        }
    };
    private final ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<Marshaller>() {
        protected synchronized Marshaller initialValue() {
            try {
                return jaxbContext.createMarshaller();
            } catch (JAXBException e) {
                throw new IllegalStateException("Unable to create marshaller");
            }
        }
    };
    
    private final JAXBContext jaxbContext;
    
    private MyClassConstructor(){
        try {
            jaxbContext = JAXBContext.newInstance(Entity.class);
        } catch (JAXBException e) {
            throw new IllegalStateException("Unable to initialize");
        }
    }
    
  • 5

    JAXB 2.2(JSR-222)在第"4.2 JAXBContext"节中有这样的说法:

    为避免创建JAXBContext实例所涉及的开销,建议JAXB应用程序重用JAXBContext实例 . 抽象类JAXBContext的实现需要是线程安全的,因此,应用程序中的多个线程可以共享同一个JAXBContext实例 . [..] JAXBContext类被设计为不可变的,因此线程安全 . 考虑到在创建JAXBContxt的新实例时可能发生的动态处理量,建议跨线程共享JAXBContext实例并尽可能重用以提高应用程序性能 .

    遗憾的是,该规范未对UnmarshallerMarshaller的线程安全提出任何声明 . 所以最好假设它们不是 .

  • 193

    更好!!基于上面帖子中的好解决方案,在构造函数中只创建一次上下文,并保存它而不是类 .

    替换线:

    private Class clazz;
    

    这一个:

    private JAXBContext jc;
    

    和这个的主要构造函数:

    private Jaxb(Class clazz)
      {
         this.jc = JAXBContext.newInstance(clazz);
      }
    

    所以在getMarshaller / getUnmarshaller中你可以删除这一行:

    JAXBContext jc = JAXBContext.newInstance(clazz);
    

    在我的情况下,这种改进使处理时间从60~70ms下降到仅5~10ms

  • 11

    我通常使用 ThreadLocal 类模式来解决这样的问题 . 鉴于您需要为每个类使用不同的编组器,您可以将其与 singleton -map模式组合 .

    为你节省15分钟的工作量 . 以下是我对Jaxb Marshallers和Unmarshallers的线程安全工厂的实现 .

    它允许您按如下方式访问实例...

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

    你需要的代码是一个小的Jaxb类,如下所示:

    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;
      }
    }
    

相关问题