【问题标题】:How do I improve performance of application that uses the JAXBContext.newInstance operation?如何提高使用 JAXBContext.newInstance 操作的应用程序的性能?
【发布时间】:2011-08-27 23:43:03
【问题描述】:

我在基于 JBoss 的 Web 应用程序中使用 JAXBContext.newInstance 操作。据我了解,这个操作非常重量级。我只需要 Marshaller 类的两个唯一实例。

我最初的建议是有一个静态初始化块,它只会在类加载时初始化这两个实例:

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(...);
            ...
    }

}

如果这是一个合理的解决方案,那么我想我会回答我自己的问题,但我想知道这是否是正确的方法?

【问题讨论】:

    标签: java xml jaxb


    【解决方案1】:

    JAXB 实现(MetroEclipseLink MOXyApache JaxMe 等)通常在 JAXBContext.newInstance 调用期间初始化其元数据。所有 OXM 工具都需要在某个时间点初始化映射元数据,并尽量减少此操作的成本。既然不可能做到零成本,最好只做一次。 JAXBContext 的实例是线程安全的,所以是的,您只需要创建一次。

    来自 JAXB 2.2 规范,第 4.2 节 JAXB 上下文:

    为了避免涉及的开销 创建一个 JAXBContext 实例,一个 鼓励 JAXB 应用程序 重用 JAXBContext 实例。一个 抽象类的实现 JAXBContext 必须是 线程安全的,因此,多个线程 一个应用程序可以共享相同的 JAXBContext 实例。

    Marshaller 和 Unmarshaller 的实例不是线程安全的,不能在线程之间共享,它们是轻量级的。

    【讨论】:

      【解决方案2】:

      我最近使用 JAXBContext.newInstance 进行了一些性能测试,结果记录在此处。

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

      当由一个线程调用时,使用一个相当大的模式并生成了大约 195 个类,它需要大约 400 毫秒才能完成。当被 20 个线程同时调用时,它会导致 cpu 争用,并且需要大约 5000 毫秒才能完成。一个小对象的编组器和对象序列化的创建也只有大约 14 毫秒。

      【讨论】:

        【解决方案3】:

        JAXBContext 应该始终是静态的,它是线程安全的。

        Marshallers 和 Unmarshallers 很便宜而且不是线程安全的。您应该创建一次 JAXBContext 并为每个操作创建编组器/解组器

        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(...);
                    ...
            }
        
        }
        

        使用相同的编组器来编组所有内容(在创建上下文时添加所有类)。

        【讨论】:

        • 只是评论:您不应该重用编组器/解组器,它们不是线程安全的。每次都创建它们,速度非常快
        • 我认为这里建议的解决方案是正确的,并且非常有帮助,但我不认为代码示例说明了文本中您不应该调用 JAXBContext.newInstance 的观点() 每次你需要一个 Marshaller 时。 doSomething() 中的行不应该是requestMarshaller = jaxbContext.createMarshaller();吗?
        【解决方案4】:

        可以使用 javax.xml.bind.JAXB。它有直接的 Marshal 和 unmarshal 方法。所以您不必担心 JAXB 的实例创建。

        例如JAXB.unmarshal(inputStream/inputFile, outputClassExpected) 或 JAXB.marshal(jaxbObject, xmlOutputFile/xmlOutputStream)

        【讨论】:

        • 您在javax.xml.bind.JAXB 类的javadoc 中看到了吗? 一般来说,性能不一定是最佳的。预计需要编写性能关键代码的人将直接使用 JAXB API 的其余部分。
        • @ThomasFritsch,是的。性能可能是关键项目的关注点。如果是这种情况,则必须检查。可能正在编写自己的 marshaller/un-marshaller 会有所帮助。
        • 在我的例子中,JAXB.marshall 使用它自己的上下文缓存实现。 Oracle JDK 8。所以事实证明,使用 Jaxb API 并且不缓存上下文会更快
        【解决方案5】:

        您应该为每个 bean 类创建一个 JAXBContext 对象。见this

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-21
          • 2021-10-06
          相关资源
          最近更新 更多