使用JAX-WS构建大型MTOM / XOP消息 [英] Building large MTOM/XOP messages with JAX-WS

查看:163
本文介绍了使用JAX-WS构建大型MTOM / XOP消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a question about using MTOM/XOP with JAX-WS. I'm writing a web service which sends large amounts of binary data. The client requests a number of files and the server returns the files in the response.

我能够正确地构建响应,以便正确实现XOP但是我遇到了与内存相关的问题,因为它在发送之前将整个响应存储在内存中。此Web服务发送的文件可以非常大(例如,giga-bytes large),因此无法将响应存储在内存中。

I'm able to get it to build the response correctly so that it correctly implements XOP, but I run into memory-related issues becasuse it stores the entire response in memory before sending it. The files this web service sends can get very large (like, giga-bytes large), so storing the response in memory is not an option.

此Oracle网站(和以及这一个)似乎解决了这个问题,但我只是没有明白它。我认为他们使用 DataHandler 对象来传输请求/响应,但我无法弄清楚它们如何实例化它。

This Oracle website (and along with this one) seems to solve this problem, but I just don't understand it. I think they use a DataHandler object to stream the request/response, but I can't figure out how they instantiate it.

我正在使用 wsimport 从现有的WSDL生成我的JAX-WS类文件。我正在使用带有Java 6的JAX-WS RI 2.1.6。

I'm generating my JAX-WS class files from an existing WSDL using wsimport. I'm using JAX-WS RI 2.1.6 with Java 6.

如何在我构建响应时发送响应而无需存储首先记在内存中?

预先感谢您的帮助。

UPDATE 12/17:我将以下属性添加到包含二进制数据的WSDL中的schema元素。这会导致 wsimport 将一个 DataHandler 对象添加到JAXB类。然后可以将 FileDataHandler 添加到响应中,而不是添加文件的全部内容,从而允许服务器流式传输每个文件的内容,而不是将它们全部保存在记忆:

UPDATE 12/17: I added the following attributes to the schema element in the WSDL that holds the binary data. This causes wsimport to add a DataHandler object to the JAXB class. A FileDataHandler can then be added to the response, instead of adding the entire contents of the file, allowing the server to stream the contents of each file, instead of holding them all in memory:

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

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

So, the server correctly builds the response now, and client properly saves each file to disk when it receives the request. However, the client still reads the entire response into memory for some reason.

服务器代码(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();
    //...
}


推荐答案

Java 6中包含JAX-WS RI(Metro或其中的一部分),客户端代码必须设置HTTP分块大小,以通过DataHandler InputStream启用大型MTOM附件的流式传输。

With JAX-WS RI included in Java 6 (Metro or part of it), the client code must set HTTP chunking size to enable streaming of large MTOM attachments through DataHandler InputStream.

((BindingProvider)port).getRequestContext()
   .put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);

但目前它因为一个错误而无效 JAX_WS-936

BUT at the moment it just not works because of a bug JAX_WS-936

因此,即使使用正确的分块和DataHandler也是如此用法,附件在服务调用时立即完全加载到内存中。我检查了网络流量:在读取DataHandler输入流之前完全内容传输,以及Java堆内存使用情况:它已经增加到包含至少三个附件副本。

As a result, even with proper chunking and DataHandler usage, an attachment gets fully loaded in memory immediately at service invocation. I have checked network traffic: full content transfert before reading DataHandler input stream, and Java heap memory usage: it has increased to contain at least three copies of the attachment.

这篇关于使用JAX-WS构建大型MTOM / XOP消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆