Spring boot SOAP Web Service Performance
This tutorial walks you through the process of consuming a SOAP-based web service
with Spring.
It elucidates following items
-
Sending large SOAP message payloads using AXIOM( AXis Object Model) AxiomSoapMessageFactory.(which improves performance)
-
Marshalling( is the process of transforming the memory representation of an object to a data format suitable for storage or transmission)
Marshalling (XML Serialization) done with O/X Mappers, different types of mappers out there and choose appropriate one for your need.
-
Castor XML mapping is an open source XML binding framework. It allows you to transform the data contained in a java object model into/from an XML document. By default, it does not require any further configuration, though a mapping file can be used to have more control over the behavior of Castor. The Spring integration classes reside in the
org.springframework.oxm.castor
package -
JiBX The JiBX framework offers a solution similar to that which JDO provides for ORM: a binding definition defines the rules for how your Java objects are converted to or from XML. After preparing the binding and compiling the classes, a JiBX binding compiler enhances the class files, and adds code to handle converting instances of the classes from or to XML. Spring integration classes resides in
org.springframework.oxm.jibx
Refer spring-web-service-example for more information.
-
XStream is a simple library to serialize objects to XML and back again. It does not require any mapping, and generates clean XML. The Spring integration classes reside in the
org.springframework.oxm.xstream
package
Note
|
XStream is an XML serialization library, not a data binding library |
-
Eclipselink Moxy Eclipselink Moxy
We will build a SOAP client that fetches city information based on zipCode
.
Complete WSDL you can found http://ws.cdyne.com/psaddress/addresslookup.asmx?wsdl
From the above WSDL we will use following simple service calls
-
ReturnCityState
- This will return City and State Information -
AlternateCities
- This will return alternate city names
Spring provides a mechanism to invoke soap based services using WebServiceTemplate
It has three main components to communicate with soap service, refer SoapTemplateConfig for full configuration.
-
Message Sender - which is responsible for sending the XML message across a transport layer(HTTP/JMS/Email)
-
Message Factory - A factory for creating SOAPMessage objects
-
Marshaller - is the process of transforming the memory representation of an object to a data format suitable for storage or transmission
Message Sender (HTTP Transport)
There are two implementations of the WebServiceMessageSender
interface for sending messages via HTTP.
-
The default implementation is the
HttpUrlConnectionMessageSender
, which uses the facilities provided by Java itself. -
The alternative is the
HttpComponentsMessageSender
, which uses theApache HttpComponents HttpClient
. Use the latter if you need more advanced and easy-to-use functionality (such as authentication, HTTP connection pooling, and so forth).
/**
* Apache httpClient with default behaviour. customize as per need to handle https traffic
*
* @return httpClient
*/
@Bean
HttpClient httpClient() {
return HttpClients.custom()
.setDefaultRequestConfig(RequestConfig.DEFAULT)
.addInterceptorFirst(httpRequestInterceptor())
.build();
}
/**
* Remove duplicate header
*/
public HttpRequestInterceptor httpRequestInterceptor() {
return (request, context) -> request.removeHeaders(HTTP.CONTENT_LEN);
}
/**
* Transportation: HTTP (Other alternative Transportation like JMS, EMAIL, XMPP)
* <p>
* There are two implementations of the {@link org.springframework.ws.transport.WebServiceMessageSender}
* interface for sending messages via HTTP.
* 1. The default implementation is the
* {@link org.springframework.ws.transport.http.HttpUrlConnectionMessageSender}, which uses the facilities
* provided by Java itself.
* <p>
* 2.The alternative is the {@link HttpComponentsMessageSender}, which uses the Apache HttpComponents
* {@link HttpClient}.
* Use the latter if you need more advanced and easy-to-use functionality (such as authentication, HTTP connection
* pooling, and so forth).
*
* @return HttpComponentsMessageSender {@link HttpComponentsMessageSender}
*/
@Bean
HttpComponentsMessageSender httpComponentsMessageSender() {
HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
httpComponentsMessageSender.setHttpClient(httpClient());
return httpComponentsMessageSender;
}
Message Factory
Concrete message implementations are created by a WebServiceMessageFactory
.
This factory can create an empty message, or read a message based on an input stream.
There are two concrete implementations of WebServiceMessageFactory;
-
one is based on SAAJ, the SOAP with Attachments API for Java,
-
the other based on Axis 2’s AXIOM, the AXis Object Model.
AxiomSoapMessageFactory
The AxiomSoapMessageFactory
uses the AXis 2 Object Model to create SoapMessage implementations.
AXIOM is based on StAX, the Streaming API for XML. StAX provides a pull-based mechanism for reading XML messages, which can be more efficient for larger messages.
To increase reading performance on the AxiomSoapMessageFactory
, you can set the payloadCaching
property to false (default is true).
This will read the contents of the SOAP body directly from the socket stream.
When this setting is enabled, the payload can only be read once.
This means that you have to make sure that any pre-processing (logging etc.) of the message does not consume it.
/**
* In addition to a message sender, the WebServiceTemplate requires a Web service message factory. There are two
* message factories for SOAP: {@link SaajSoapMessageFactory} and
* {@link AxiomSoapMessageFactory}. If no message factory is
* specified (via the messageFactory property), Spring-WS will use the
* {@link org.springframework.ws.soap.saaj.SaajSoapMessageFactory} by default.
* <p>
* The AxiomSoapMessageFactory uses the AXis 2 Object Model to create SoapMessage implementations. AXIOM is based
* on StAX, the Streaming API for XML. StAX provides a pull-based mechanism for reading XML messages, which can
* be more efficient for larger messages.
*
* @return AxiomSoapMessageFactory {@link AxiomSoapMessageFactory}
*/
@Bean
AxiomSoapMessageFactory axiomSoapMessageFactory() {
AxiomSoapMessageFactory axiomSoapMessageFactory = new AxiomSoapMessageFactory();
/*
* To increase reading performance on the AxiomSoapMessageFactory, you can set the payloadCaching property to
* false (default is true). This will read the contents of the SOAP body directly from the socket stream.
* When this setting is enabled, the payload can only be read once. This means that you have to make sure
* that any pre-processing (logging etc.) of the message does not consume it.
*/
axiomSoapMessageFactory.setPayloadCaching(false);
//axiomSoapMessageFactory.afterPropertiesSet();
return axiomSoapMessageFactory;
}
Sending and receiving POJOs - marshalling and un-marshalling
In order to facilitate the sending of plain Java objects, the WebServiceTemplate has a number of send(..)
methods
that take an Object as an argument for a message’s data content.
The method marshalSendAndReceive(..)
in the WebServiceTemplate class delegates the conversion of the request object to XML to a Marshaller
,
and the conversion of the response XML to an object to an Unmarshaller
.
To externalize the conversion logic we use Eclipselink Moxy
Framework.
Eclipselink Moxy
Refer https://wiki.eclipse.org/EclipseLink/Examples document for more information.
/**
* Handles conversion of JavaObjects to XML vice versa. (uses MOXY to externalize this conversion).
* <p>
* In order to facilitate the sending of plain Java objects, the WebServiceTemplate has a number of send(..)
* methods that take an Object as an argument for a message's data content. The method marshalSendAndReceive(..)
* in the WebServiceTemplate class delegates the conversion of the request object to XML to a Marshaller, and the
* conversion of the response XML to an object to an Unmarshaller.
*
* @return Jaxb2Marshaller {@link Jaxb2Marshaller}
*/
public Jaxb2Marshaller jaxb2Marshaller(String path) throws IOException {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("bindings/" + path + "/**");
Map<String, Object> properties = Collections.singletonMap(JAXBContextProperties.OXM_METADATA_SOURCE,
Arrays.stream(resources).map(resource -> "bindings/" + path
+ "/" + resource.getFilename()).collect(Collectors.toList()));
LOGGER.info("JaxbContextProperties {} ", properties);
jaxb2Marshaller.setJaxbContextProperties(properties);
//used to specify java classes to bound. since we are using Moxy we need to provide
//jaxb.properties file folder - javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
jaxb2Marshaller.setContextPath("jaxb");//jaxb.context.path
return jaxb2Marshaller;
}
Client layer uses RxJava to make asynchronous calls and aggregates the result.
refer Github repository for complete codebase.
Summary
-
Invoking SOAP web service using webServiceTemplate
-
Understanding the different messageFactories (
Axiom
and SAAJ) -
Different message senders for different protocols (
HTTP
, JMS etc) -
Integrating
Moxy
Marshaller framework( Java to XML conversion) -
Usage of RxJava for parallel calls
Comments
Post a Comment