使用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)也可以被抽真空。
答案 0 :(得分:1)
见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