2011-05-18 27 views
14

我在基于JBoss的Web应用程序中使用JAXBContext.newInstance操作。据我了解,这个操作非常重量级。我只需要两个Marshaller类的独特实例。如何提高使用JAXBContext.newInstance操作的应用程序的性能?

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

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

} 

如果这是一个合理的解决方案,然后我想我会回答我自己问题,但我想知道这是否是正确的方法来做到这一点?

回答

24

JAXB实现(Metro,EclipseLink MOXy,Apache JaxMe等)通常会在调用JAXBContext.newInstance期间初始化其元数据。所有OXM工具都需要在某个时候初始化映射元数据,并尽量降低此操作的成本。由于不可能以零成本实现,所以最好只做一次。 JAXBContext的实例是线程安全的,所以是的,你只需要创建一次。

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

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

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

6

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

} 

使用相同的编组,以马歇尔一切(加上所有类当你创建上下文)创建marshallers/unmarshallers。

+2

只是一个评论:你不应该重用marshallers/unmarshallers,它们不是线程安全的。每次都创建它们,速度非常快 – cocorossello 2015-06-03 11:04:15

+2

我认为这里提出的解决方案是专注的,并且非常有帮助,但我不相信代码示例说明了文本中所指出的您不应该调用JAXBContext .newInstance()每次你需要一个Marshaller。不应该doSomething()中的行是'requestMarshaller = jaxbContext.createMarshaller();'? – rscarter 2015-09-23 18:14:57

0

可以使用javax.xml.bind.JAXB。它有直接的元帅和解组方法。所以你不必担心JAXB的实例创建。

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

+0

您是否在类[javax.xml.bind.JAXB](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXB.html)的javadoc中看到了此内容? *一般来说,表现不一定是最佳的。预计需要编写性能关键代码的人将直接使用其余的JAXB API。* – 2017-09-11 16:19:58

+0

@ThomasFritsch,是的。表现可能是关键项目的关注点。这是必须检查,如果是这样的话。可能会编写自己的编组/编组将有所帮助。 – 2017-09-14 12:07:49