Spring WS 4.x迁移至5.x后Axiom MTOM附件读取异常求助
Spring WS 5.x + Axiom 1.4 MTOM 附件读取异常解决方案
核心原因
Axiom 1.4 对 MemoryBlobImpl 的行为做了调整:当构建SOAP消息时如果preserve参数设为false,附件对应的内存Blob会在首次读取后立即释放内容。而你的场景中,Spring WS在转换SOAP消息时默认用了preserve=false,导致Camel Exchange添加附件后二次读取流时触发IllegalStateException。
解决方案
1. 全局修改Axiom构建时的preserve参数
通过自定义AxiomMessageFactory,强制设置构建SOAP消息时的preserve为true,让附件内容保留在内存中支持多次读取:
@Bean public AxiomMessageFactory axiomMessageFactory() { AxiomMessageFactory messageFactory = new AxiomMessageFactory(); // 配置BuilderSpec,开启preserve模式 messageFactory.setBuilderSpec(BuilderSpec.from().preserve(true)); return messageFactory; }
将这个Bean注入到Spring WS的端点配置中,替换默认的消息工厂即可。
2. 局部复制附件流(无需全局修改)
如果不想全局调整Axiom的行为,可以在Camel Bean中提前将附件流复制到可重复读取的载体中,比如ByteArrayInputStream:
import org.apache.commons.io.IOUtils; import javax.activation.DataHandler; import javax.mail.util.ByteArrayDataSource; import org.apache.camel.AttachmentMessage; // Bean中的处理逻辑 public void processAttachments(Exchange exchange) throws IOException { AttachmentMessage attachmentMsg = exchange.getIn(AttachmentMessage.class); Map<String, DataHandler> attachments = attachmentMsg.getAttachments(); for (Map.Entry<String, DataHandler> entry : attachments.entrySet()) { DataHandler originalDh = entry.getValue(); // 读取原流内容到字节数组 byte[] attachmentContent = IOUtils.toByteArray(originalDh.getInputStream()); // 创建新的DataHandler,使用可重复读取的ByteArrayDataSource DataHandler reusableDh = new DataHandler( new ByteArrayDataSource(attachmentContent, originalDh.getContentType()) ); entry.setValue(reusableDh); } // 后续读取reusableDh.getInputStream()不会再触发异常 }
注意需要引入commons-io依赖来使用IOUtils,也可以手动实现流复制逻辑。
3. 检查集成流程顺序
确保Spring WS的SOAP消息解析完成后,再触发Camel的附件提取逻辑,避免附件流被提前消费。同时确认发送端soapmessage#setOptimized的配置正确,MTOM消息的MIME边界和附件标识符合规范。
参考示例与测试用例
- Spring WS源码中的
AxiomMtomMessageTest:包含MTOM消息解析、附件读取的核心场景,展示了如何正确配置Axiom处理MTOM。 - Camel的
SpringWsMtomTest:属于camel-spring-ws组件的测试用例,演示了Camel与Spring WS集成时处理MTOM附件的完整流程。
内容的提问来源于stack exchange,提问作者R.Groote
相关产品推荐
相关产品推荐

