Давайте познакомимся с терминами SOAP Message
Transmission Optimization Mechanism/XML-binary Optimized Packaging (MTOM/XOP). При передаче больших бинарных
данных в протоколе SOAP,
таких как большие строки, рисунки, музыкальные файлы, они обычно кодируются в
два xml schema типа это xs:base64Binary или xs:hexBinary. Кодирование/раскодирование в эти типы отнимает
много времени у программ, по этому предложили простой выход, применять
оптимизацию передачи двоичных данных, так появился термин MTOM. MTOM для оптимизации больших
бинарных данных использует механизм XOP, который описан в официальной
спецификации https://www.w3.org/TR/2005/REC-soap12-mtom-20050125/ . Для начала я вам покажу пример без MTOM, в дальнейшем мы подключим этот механизм
и посмотрим в чем различие. Берем пример из прошлой статьи и дорабатываем его,
добавим метод принимающий бинарные данные void getBinary(byte[] b):
package com.lopanov;
import
javax.jws.WebService;
@WebService
public interface
HelloWorld {
Person sayHi(String text);
void
getBinary(byte[] b);
}
Допишем реализацию нашего web сервиса, который получает бинарные данные и выводит их в стандартный
вывод System.out:
package com.lopanov;
import
org.apache.cxf.annotations.Logging;
import
javax.jws.WebService;
import
java.io.IOException;
import java.util.GregorianCalendar;
@WebService(endpointInterface
= "com.lopanov.HelloWorld")
@Logging
public class
HelloWorldImpl implements HelloWorld {
public Person sayHi(String text) {
Person person = new Person(text,
"Lopanov", new GregorianCalendar(1981, 8, 23));
return person;
}
@Override
public void getBinary(byte[] b) {
try {
System.out.write(b);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Перепишем нашего клиента
из прошлой статьи:
package com.lopanov;
import
com.sun.xml.ws.developer.StreamingAttachmentFeature;
import javax.xml.namespace.QName;
import javax.xml.ws.Endpoint;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import java.io.File;
import java.io.FileInputStream;
public class Main1 {
private
static final QName SERVICE_NAME = new QName("http://lopanov.com/",
"HelloWorld");
private
static final QName PORT_NAME = new QName("http://lopanov.com/",
"HelloWorldPort");
public
static void main(String args[]) throws Exception {
System.out.println("Starting Server");
HelloWorldImpl implementor = new HelloWorldImpl();
String
address = "http://localhost:9000/helloWorld";
Endpoint.publish(address, implementor);
Service
service = Service.create(SERVICE_NAME);
//
Endpoint Address
String
endpointAddress = "http://localhost:9000/helloWorld";
// Add a
port to the Service
service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING,
endpointAddress);
HelloWorld hw = service.getPort(HelloWorld.class);
File
file = new File("c:/11.txt");
FileInputStream
fis = new FileInputStream(file);
byte[] b
= new byte[1024*10];
fis.read(b,0,b.length);//прочитаем наш файл c:/11.txt в байтовый массив
hw.getBinary(b);//вызовем
операцию web сервиса и
передадим ему бинарные данные
//System.out.println(hw.sayHi("World"));
System.exit(0);
}
}
Мы получили такой SOAP лог:
….
[qtp138776324-17] INFO
org.apache.cxf.services.HelloWorldImplService.HelloWorldImplPort.HelloWorld -
Inbound Message
----------------------------
ID: 1
Address: http://localhost:9000/helloWorld
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], Cache-Control=[no-cache],
connection=[keep-alive], content-type=[text/xml; charset=UTF-8],
Host=[localhost:9000], Pragma=[no-cache], SOAPAction=[""],
transfer-encoding=[chunked], User-Agent=[Apache-CXF/3.1.7]}
Payload: <soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>
<ns2:getBinary
xmlns:ns2="http://lopanov.com/">
<arg0>cm91dGUgYWRkIDEw
….
Вырезал информацию, т.к. много данных
….
09PT09PT09PT09PQ==</arg0>
</ns2:getBinary>
</soap:Body></soap:Envelope>
….
Исследуя полученный лог,
мы приходим к выводу что наши бинарные данные передаются в теле SOAP сообщения
и “закодированы”, заметьте этот термин, а не просто переданы, в тип xml schema “xs:base64Binary”
или “xs:hexBinary”. Для того что бы точно узнать заглянем в wsdl файл и уточним тип:
…
<xs:complexType
name="getBinary">
<xs:sequence>
<xs:element minOccurs="0"
name="arg0" type="xs:base64Binary"/>
</xs:sequence>
</xs:complexType>
…
При любом кодировании
или раскодировании, теряется драгоценное время, программа становиться
медленней, поэтому нужно стараться избегать таких проблем. Давайте добавим в
наш пример использование MTOM,
которое поможет нам избавиться от лишнего кодирования/раскодирования бинарных
данных в формат xs:base64Binary. Что делает MTOM/XOP, он любые бинарные
данные включает в сообщение SOAP без какой-либо
перекодировки. Задействовать механизм можно двумя способами, на клиенте с
помощью класса MTOMFeature(), который принимает два параметра, первый параметр enabled имеет тип boolean, выставив его в true вы включаете механизм MTOM, второй параметр имеет
название threshold вы указываете количество байт, так сказать
пороговое значение, при превышении
которого, будет включен механизм MTOM, если вы пересылаете меньше байт, то будет
произведено кодирование xs:base64Binary.
Перепишем клиента:
public
static void main(String args[]) throws Exception {
System.out.println("Starting Server");
HelloWorldImpl implementor = new HelloWorldImpl();
String
address = "http://localhost:9000/helloWorld";
Endpoint.publish(address, implementor);
Service
service = Service.create(SERVICE_NAME);
//
Endpoint Address
String
endpointAddress = "http://localhost:9000/helloWorld";
// Add a
port to the Service
service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING,
endpointAddress);
HelloWorld hw = service.getPort(HelloWorld.class, new MTOMFeature(true,0));//подключаем MTOM
File
file = new File("c:/11.txt");
FileInputStream fis = new FileInputStream(file);
byte[] b
= new byte[1024*10];
fis.read(b,0,b.length);//прочитаем наш файл c:/11.txt в байтовый массив
hw.getBinary(b);//вызовем
операцию web сервиса и
передадим ему бинарные данные
//System.out.println(hw.sayHi("World"));
System.exit(0);
}
Получаем такой SOAP лог:
[qtp138776324-15] INFO
org.apache.cxf.services.HelloWorldImplService.HelloWorldImplPort.HelloWorld -
Inbound Message
----------------------------
ID: 1
Address: http://localhost:9000/helloWorld
Encoding: ISO-8859-1
Http-Method: POST
Content-Type: multipart/related;
type="application/xop+xml";
boundary="uuid:4499dc67-2a40-48d3-9095-9880caebb91c";
start="<root.message@cxf.apache.org>";
start-info="text/xml"
Headers: {Accept=[*/*], Cache-Control=[no-cache],
connection=[keep-alive], content-type=[multipart/related;
type="application/xop+xml";
boundary="uuid:4499dc67-2a40-48d3-9095-9880caebb91c";
start="<root.message@cxf.apache.org>";
start-info="text/xml"], Host=[localhost:9000], Pragma=[no-cache],
SOAPAction=[""], transfer-encoding=[chunked],
User-Agent=[Apache-CXF/3.1.7]}
Payload: --uuid:4499dc67-2a40-48d3-9095-9880caebb91c
Content-Type: application/xop+xml; charset=UTF-8;
type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:getBinary
xmlns:ns2="http://lopanov.com/">
<arg0><xop:Include
xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:57fbcfca-9232-4f3b-b9c0-86a3c57b3902-1@cxf.apache.org"/></arg0>
</ns2:getBinary></soap:Body></soap:Envelope>
--uuid:4499dc67-2a40-48d3-9095-9880caebb91c
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID:
<57fbcfca-9232-4f3b-b9c0-86a3c57b3902-1@cxf.apache.org>
route add 10.0.0.0 10.152.30.1
….
Бинарный
текст пропущен
….
0.0.0.0
0.0.0.0 10.152.30.1 ® 㬮«ç ¨î
======================================
--uuid:4499dc67-2a40-48d3-9095-9880caebb91c—
И так мы видим что в SOAP теле
появилось включение бинарных данных, посредством ссылки XOP: <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="cid:57fbcfca-9232-4f3b-b9c0-86a3c57b3902-1@cxf.apache.org"/> Осталось
показать как включать MTOM на стороне web сервиса, происходит
это при помощи аннотации @MTOM,
у нее есть два параметра, enabled если
выставлено в true,
значит включен MTOM, и
threshold – порог в байтах, при превышении которого используется
XOP передача данных, аналогично классу MTOMFeature(). Смотрим на код web сервиса:
package com.lopanov;
import javax.jws.WebService;
import javax.xml.ws.soap.MTOM;
@WebService
@MTOM(enabled =
true,threshold = 0)
public interface HelloWorld {
Person
sayHi(String text);
void getBinary(byte[] b);
}
Комментариев нет:
Отправить комментарий