使用 JAX-WS 构建大型 MTOM/XOP 消息

2024-02-01

我有一个关于将 MTOM/XOP 与 JAX-WS 一起使用的问题。我正在编写一个发送大量二进制数据的网络服务。客户端请求多个文件,服务器在响应中返回文件。

我能够让它正确构建响应,以便它正确实现 XOP,但我遇到了与内存相关的问题,因为它存储了entire发送之前在内存中响应。该Web服务发送的文件可以获得very大(例如千兆字节大),因此不能将响应存储在内存中。

这个甲骨文网站 http://download.oracle.com/docs/cd/E12840_01/wls/docs103/webserv_adv/mtom.html#wp279644(并与this one https://metro.dev.java.net/guide/Large_Attachments.html)似乎解决了这个问题,但我只是不明白。我认为他们使用DataHandler对象来流式传输请求/响应,但我无法弄清楚他们如何实例化它。

我正在使用现有的 WSDL 生成 JAX-WS 类文件wsimport。我正在将 JAX-WS RI 2.1.6 与 Java 6 结合使用。

如何在构建响应时发送响应,而不必先将其全部存储在内存中?

在此先感谢您的帮助。


12/17 更新:我将以下属性添加到保存二进制数据的 WSDL 中的架构元素。这导致wsimport添加一个DataHandlerJAXB 类的对象。 AFileDataHandler然后可以添加到响应中,而不是添加文件的全部内容,允许服务器流式传输每个文件的内容,而不是将它们全部保存在内存中:

xmlns:xmime="http://www.w3.org/2005/05/xmlmime" 
xmime:expectedContentTypes="application/octet-stream"

因此,服务器现在正确地构建响应,并且客户端在收到请求时正确地将每个文件保存到磁盘。然而,由于某种原因,客户端仍然将整个响应读取到内存中。


服务器代码 (SIB):

@MTOM
@StreamingAttachment(parseEagerly = true, memoryThreshold = 4000000L) 
@WebService(...)
public class DownloadFilesPortTypeImpl implements DownloadFilesPortType {
 @Override
 public FileSetResponseType downloadFileSet(FileSetRequestType body) {
        FileSetResponseType response = new FileSetResponseType();
        for (FileRequest freq : body.getFileRequest()){
            try{
                //find the file on disk
                File file = findFile(freq.getFileId());

                //read the file data into memory
                byte[] fileData;
                {
                    FileInputStream in = new FileInputStream(file);
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    byte buf[] = new byte[8192];
                    int read;
                    while ((read = in.read(buf)) != -1){
                         out.write(buf, 0, read);
                    }
                    in.close();
                    out.close();
                    fileData = out.toByteArray();
                }

                //add the file to the response
                FileResponse fresp = new FileResponse();
                fresp.setFileId(freq.getFileId());
                fresp.setData(fileData); //<-- type "xs:base64Binary"
                response.getFileResponse().add(fresp);
            }
            catch (IOException e){
            }
        }

        return response;
 }
}

客户端代码:

DownloadFilesService service = new DownloadFilesService();
MTOMFeature mtomFeature = new MTOMFeature();
StreamingAttachmentFeature stf = new StreamingAttachmentFeature(null, true, 4000000L);
DownloadFilesPortType port = service.getDownloadFilesPortSoap12(mtomFeature, stf);

FileSetRequestType request = new FileSetRequestType();

FileRequest freq = new FileRequest();
freq.setFileId("1234");
request.getFileRequest().add(freq);

freq = new FileRequest();
freq.setFileId("9876");
request.getFileRequest().add(freq);

//...

FileSetResponseType response = port.downloadFileSet(request); //reads entire response into memory
for (FileResponse fres : response.getFileResponse()){
    byte[] data = fres.getFileData();
    //...
}

你创建自己的类来实现DataSource并构造将其传入的 DataHandler。它甚至可以是匿名的。

在 Apache CXF 中,我们使这一切变得更加容易。您可以只拥有一个返回 DataSource 或 DataHandler 的“getter”。您发布的代码中的复杂方案对我来说并不熟悉。

我认为同样的方法也适用于 JDK 的 JAX-WS+JAXB。看this http://cwiki.apache.org/CXF20DOC/mtom-attachments-with-jaxb.html.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 JAX-WS 构建大型 MTOM/XOP 消息 的相关文章

随机推荐