Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用JAX-WS构建大型MTOM/XOP消息_Java_Soap_Jax Ws_Mtom_Xop - Fatal编程技术网

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

Java 使用JAX-WS构建大型MTOM/XOP消息,java,soap,jax-ws,mtom,xop,Java,Soap,Jax Ws,Mtom,Xop,我有一个关于在JAX-WS中使用MTOM/XOP的问题。我正在编写一个web服务,它发送大量二进制数据。客户端请求许多文件,服务器在响应中返回这些文件 我能够让它正确地构建响应,从而正确地实现XOP,但我遇到了与内存相关的问题,因为它在发送响应之前将整个响应存储在内存中。此web服务发送的文件可能会变得非常大(比如千兆字节),因此将响应存储在内存中不是一个选项 (和)似乎解决了这个问题,但我就是不明白。我认为他们使用一个DataHandler对象来流化请求/响应,但我不知道他们是如何实例化它的

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

我能够让它正确地构建响应,从而正确地实现XOP,但我遇到了与内存相关的问题,因为它在发送响应之前将整个响应存储在内存中。此web服务发送的文件可能会变得非常大(比如千兆字节),因此将响应存储在内存中不是一个选项

(和)似乎解决了这个问题,但我就是不明白。我认为他们使用一个
DataHandler
对象来流化请求/响应,但我不知道他们是如何实例化它的

我正在使用
wsimport
从现有WSDL生成JAX-WS类文件。我将JAX-WSRI2.1.6与Java6一起使用

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

提前感谢你的帮助


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

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
,并构造传入它的数据处理程序。它甚至可以是匿名的

在ApacheCXF中,我们使实现这一点更加容易。您可以只使用一个返回数据源或数据处理程序的“getter”。您发布的代码中的详细方案我并不熟悉


我认为同样的方法也适用于JDK的JAX-WS+JAXB。请参阅。

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

((BindingProvider)port).getRequestContext()
   .put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
但目前它只是因为一个bug而不起作用


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

我将把数据源放在哪里?我是否需要向SEI/SIB“downloadFileSet”方法添加一个参数(我不希望这样做,因为SEI是由wsimport自动生成的)?感谢链接。我将“xmime:expectedContentTypes”添加到WSDL类型部分的相应元素中,这导致wsimport在JAX bean中创建DataHandler对象。服务器正在创建响应,但我仍然在客户端收到OutOfMemoryError异常。我检查了我的临时文件夹,它正确地保存了超过4MB的所有文件(如“StreamingAttachmentFeature”对象中所指定的)…因此,这就像是将它们写入磁盘并存储在内存中。现在,您处于Sun参考实现的特定行为范围内。也许你应该提出一个新问题,有人会帮助你。或者您可以使用CXF:-)呃……我已经走了这么远,我不想现在就切换实现,但也许我必须这样做。