我有 web 服务来接收和发送附件,我想使用 JAXB 作为编组器,但到目前为止它不能正常工作,因为 JAXB 将消息正文中传入或传出的任何附件作为 base64 字符串内联,消耗了很多内存不足并经常导致 OutOfMemoryError。我正在概述我的设置和修复尝试,希望有人能帮助我把它做好。
Axiom 是我选择 SAAJ 作为消息工厂的选择,因为我必须处理大附件。我可以成功地将 JAXB 用作端点方法的参数和返回类型的编组器,除非涉及附件(内联问题)。这是我的设置:
网络服务配置 XML:
<beans xmlns=...>
<context:component-scan base-package="com.example.webservice" />
<sws:annotation-driven />
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.example.webservice.oxm.FileTestResponse</value>
<value>com.example.webservice.oxm.FileTestRequest</value>
</list>
</property>
<property name="mtomEnabled" value="true"/>
</bean>
<bean id="messageFactory" class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
<property name="payloadCaching" value="true"/>
<property name="attachmentCaching" value="true"/>
</bean>
<sws:dynamic-wsdl id="fileTest" portTypeName="fileTest" locationUri="/webservice/fileTest/" targetNamespace="http://example.com/webservice/definitions" >
<sws:xsd location="/WEB-INF/fileTest.xsd" />
</sws:dynamic-wsdl>
</beans>
我的 XSD 的一部分:
<!-- I generate the marshalling classes with XJB, and using
xmime:expectedContentTypes it correctly creates mtomData field
with DataHandler type instead of byte[] -->
<xs:element name="fileTestRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="mtomData" type="xs:base64Binary"
xmime:expectedContentTypes="application/octet-stream"/>
</xs:sequence>
</xs:complexType>
</xs:element>
我的端点类:
package com.example.webservice;
import ...
@Endpoint
@Namespace(prefix = "s", uri = FileTestEndpoint.NAMESPACE)
public class FileTestEndpoint {
public static final String NAMESPACE = "http://example.com/webservice/schemas";
@PayloadRoot(localPart = "fileTestRequest", namespace = NAMESPACE)
@ResponsePayload
public FileTestResponse fileTest(@RequestPayload FileTestRequest req) throws IOException {
// req.getMtomData() and do something with it
FileTestResponse resp = new FileTestResponse();
DataHandler dataHandler = new DataHandler(new ByteArrayDataSource("my file download data".getBytes(), "text/plain"));
resp.setData(dataHandler);
return resp;
}
}
因此,此代码有效,但与附件不同。我正在寻找一些工作解决方案:
- Spring 论坛:正确的 MTOM 处理?: 建议扩展一些 Axiom 类,但自(2008 年)以来代码发生了很大变化,我无法让它工作;
- Spring 论坛:Response-Attachment/Saaj/Jaxb:可能是由 1.6u14 中修复的 JVM 错误引起的,这是我的 Weblogic 版本使用的错误(另外它不适用于主题创建者);
- Spring 论坛:使用 Spring-WS 客户端发送大型附件:有人使用 Axis2 解决了直接绕过 Spring WS,这不是重点;
- Stackoverflow:带有 MTOM 附件的 Spring-WS webservice - Hello world 测试:与我的问题相同,2 周前,没有答案;
显然,最好的帮助来自我发布的关于 WSS4J 发生的这个内联问题的另一个 SO question 。Blaise Doughan 说我需要AttachmentMarshaller
并AttachmentUnmarshaller
设置(un)marshaller 来正确处理它,就像他在他的博客中发布的那样。
所以,我假设附件编组器是解决这个问题的关键。
要将它们设置在(un)marshaller 上,我没有其他办法,只能在给定的(un)marshaller 上设置附件 marshaller(我为它们复制了 Doughan 的代码Jaxb2Marshaller
)initJaxbMarshaller
。initJaxbUnmarshaller
但是我自己Jaxb2Marshaller
的没有被使用,即使手动设置为sws:annotation-driven
:
<sws:annotation-driven marshaller="jaxb2Marshaller" unmarshaller="jaxb2Marshaller"/>
<bean id="jaxb2Marshaller" class="com.example.webservice.MyJaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.example.webservice.oxm.FileTestResponse</value>
<value>com.example.webservice.oxm.FileTestRequest</value>
</list>
</property>
<property name="mtomEnabled" value="true"/>
</bean>
这个 marshaller 类是创建但从未使用过,我不知道为什么,所以我仍然无法测试AttachmentMarshaller
s 是否可以解决问题。
这就是我现在能说的。有很多方法可以尝试:
- 找出
MyJaxb2Marshaller
被忽略的原因,这可能是最简单的; AttachmentMarshaller
如果s 不能解决它,则修复 JAXB 附件内联其他方式,我不知道那会是什么;- 用其他编组器替换 JAXB,效果一样好(主要是 Axiom 支持,可能是 WSS4J)。
我在这个问题上待了很长时间,我一定错过了明显的解决方案。任何帮助都是最受欢迎的。
谢谢!
库版本:
- Spring 3.1.0 (core, beans, oxm 等)
- Spring WS 2.1.0(核心和 Spring XML)
- StAX2 2.1
- WoodSToX 3.2.9 (wstx)
- JAXB 2.2.5-2 (API+impl)
- Apache Axiom 1.2.13 (API+impl+c14n+dom)
- Apache Mime4j 0.7.2(核心)
应用服务器是带有 Java 1.6.0u14 的 Oracle 11g R1 Patchset 1。