Создание большого MTOM/XOP обменивается сообщениями с JAX-WS

У меня есть вопрос об использовании MTOM/XOP с JAX-WS. Я пишу веб-сервис, который отправляет большие объемы двоичных данных. Клиент запрашивает много файлов, и сервер возвращает файлы в ответе.

Я могу заставить это создавать ответ правильно так, чтобы это правильно реализовало XOP, но я сталкиваюсь со связанными с памятью проблемами becasuse, это хранит весь ответ в памяти прежде, чем отправить его. Файлы, которые отправляет этот веб-сервис, могут стать очень большими (как, большие гигабайты), так хранение ответа в памяти не является опцией.

Этот веб-сайт Oracle (и наряду с этим), кажется, решает эту проблему, но я просто не понимаю это. Я думаю, что они используют a DataHandler возразите для потоковой передачи запроса/ответа, но я не могу выяснить, как они инстанцируют его.

Я генерирую свои файлы класса JAX-WS от существующего использования WSDL wsimport. Я использую JAX-WS RI 2.1.6 с Java 6.

Как я отправляю ответ, поскольку я создаю его, не имея необходимость хранить всего в памяти сначала?

Заранее спасибо за Вашу справку.


ОБНОВЛЕНИЕ 12/17: Я добавил следующие атрибуты к элементу схемы в WSDL, который содержит двоичные данные. Это вызывает wsimport добавить a DataHandler возразите против класса JAXB. A FileDataHandler может затем быть добавлен к ответу, вместо того, чтобы добавить все содержание файла, позволив серверу передать содержание потоком каждого файла, вместо того, чтобы содержать их всех в памяти:

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

Так, сервер правильно создает ответ теперь, и клиент правильно сохраняет каждый файл на диск, когда он получает запрос. Однако клиент все еще читает весь ответ в память по некоторым причинам.


Серверный код (РОДСТВО):

@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();
    //...
}

6
задан Michael 17 December 2009 в 21:56
поделиться

1 ответ

Вы создаете свой собственный класс, который реализует DataSource , и создаете DataHandler, передающий его. Он может быть даже анонимным.

В Apache CXF, мы сделали это намного проще. У вас может быть просто «геттер», который возвращает DataSource или DataHandler. Сложная схема в опубликованном вами коде мне не знакома.

Я думаю, что те же методы работают с JAX-WS + JAXB JDK. См. это .

2
ответ дан 17 December 2019 в 07:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: