带有大消息的JAX-WS SoapHandler:OutOfMemoryError

时间:2013-03-17 14:58:52

标签: soap jax-ws soaphandler

使用JAX-WS 2,我看到其他人也谈到了一个问题。问题是如果在处理程序内部接收到SOAP消息,并且SOAP消息很大 - 无论是由于内联SOAP主体元素碰巧有大量内容,还是由于MTOM附件 - 那么获取一个很容易的OutOfMemoryError。

原因是对getMessage()的调用似乎引发了一系列事件,这些事件涉及在线上读取整个SOAP消息,以及创建表示线路上的内容的对象(或多个对象)。

例如:

...
public boolean handleMessage(SOAPMessageContext context)
{
    // for a large message, this will cause an OutOfMemoryError
    System.out.println( context.getMessage().countAttachments() );
...

我的问题是:是否有一个已知的机制/解决方法来处理这个问题?具体来说,在SOAP消息中访问SOAP部分而不强制附件(例如,如果MTOM)也可以被抽真空。

4 个答案:

答案 0 :(得分:1)

实际上,JAX-WS RI(又名Metro)的具体解决方案非常有效。

https://javaee.github.io/metro/doc/user-guide/ch02.html#efficient-handlers-in-jax-ws-ri。不幸的是,这个链接现在已被破坏,但您可以在WayBack Machine上找到它。我将在下面给出重点:

Metro大约在2007年introduced增加了一个处理程序类型MessageHandler<MessageHandlerContext>,这是Metro专有的。它比SOAPHandler<SOAPMessageContext>更有效率,因为它没有尝试进行内存中的DOM表示。

以下是原始博客文章中的重要文字:

  

的MessageHandler:

     

利用JAX-WS提供的可扩展Handler框架   我们介绍了RI中的规范和更好的Message抽象   一个名为MessageHandler的新处理程序,用于扩展您的Web服务   应用。 MessageHandler类似于SOAPHandler,除了   它的实现可以访问MessageHandlerContext(an   MessageContext的扩展)。通过MessageHandlerContext可以   访问Message并使用Message API处理它。正如我所说的那样   博客的标题,这个处理程序让你可以使用Message,它   提供访问/处理消息的有效方法,而不仅仅是DOM   基于消息。处理程序的编程模型是相同的   消息处理程序可以与标准的逻辑和SOAP处理程序混合使用。   我在JAX-WS RI 2.1.3中添加了一个示例,展示了它的用法   MessageHandler用于记录消息,这里是样本的片段:

public class LoggingHandler implements MessageHandler<MessageHandlerContext> {
    public boolean handleMessage(MessageHandlerContext mhc) {
        Message m = mhc.getMessage().copy();
        XMLStreamWriter writer = XMLStreamWriterFactory.create(System.out);
        try {
            m.writeTo(writer);
        } catch (XMLStreamException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean handleFault(MessageHandlerContext mhc) {
        ..... 
        return true;
    }

    public void close(MessageContext messageContext) {    }

    public Set getHeaders() {
        return null;
    }
}

(2007年博文最后引用)

您可以在full example中找到Metro GitHub repo

答案 1 :(得分:1)

对于那些在JBoss 6和7(使用Apache CXF)上运行其应用程序的人...通过从LogicalHandler接口而不是SOAPHandler实现我的处理程序,我能够解决问题。 在这种情况下,您的handleMessage()方法将在与context.getMessage()调用没有问题的参数中获取LogicalMessageContext上下文(而不是SOAPMessageContext)

答案 2 :(得分:0)

您使用的是哪种JAX-WS实现运行时?如果有一种方法可以使用WebSphere内置的运行时执行此操作,我确定有一种方法可以在其他运行时(如Axis2(正确),Apache CXF和Metro / RI)中干净地执行此操作。

答案 3 :(得分:0)

我正在使用另一种方法来减少内存成本,即Message Accessor

我没有使用context.getMessage(),而是将其改为:

Object accessor = context.get("jaxws.message.accessor");

if (accessor != null) {
                baosInString = accessor.toString();
                }

基于IBM网站的建议。 http://www-01.ibm.com/support/docview.wss?uid=swg1PM21151