Reputation: 5255
I am using spring WebServiceTemplate as a web service client programmatically i.e. without instantiating a spring container. I am using Jaxb2Marshaller for marshaling/unmarshaling. In my application, I create a single instance of the SaajSoapMessageFactory and one instance of Jaxb2Marshaller. I also create a single instance of the WebServiceTemplate and assign the previously created instances of SaajSoapMessageFactory and Jaxb2Marshaller.
The WebServiceTemplate I created is used in a multi threaded way i.e. multiple threads can call marshalSendAndReceive at the same time. My question is - is my configuration thread safe? I am concerned about the Jaxb2Marshaller. The javadoc says Jaxb2Marshallers are not necessarily thread safe. How can I use the Jaxb2Marshaller in a thread safe way without reinitializing the Jaxb context?
As an aside: looking at the example spring-ws configuration in the spring reference leads me to believe that the Jaxb2Marshaller is thread safe but the Javadoc seems to contradict that.
Upvotes: 7
Views: 9109
Reputation: 127
The class org.springframework.oxm.jaxb.Jaxb2Marshaller is thread safe, since it creates for every marshalling event new instance of javax.xml.bind.Marshaller, see the original source code from Spring 5.2.6:
@Override
public void marshal(Object graph, Result result, @Nullable MimeContainer mimeContainer) throws XmlMappingException {
try {
Marshaller marshaller = createMarshaller();
if (this.mtomEnabled && mimeContainer != null) {
marshaller.setAttachmentMarshaller(new Jaxb2AttachmentMarshaller(mimeContainer));
}
if (StaxUtils.isStaxResult(result)) {
marshalStaxResult(marshaller, graph, result);
}
else {
marshaller.marshal(graph, result);
}
}
catch (JAXBException ex) {
throw convertJaxbException(ex);
}
}
/**
* Return a newly created JAXB marshaller.
* <p>Note: JAXB marshallers are not necessarily thread-safe.
* This method is public as of 5.2.
* @since 5.2
* @see #createUnmarshaller()
*/
public Marshaller createMarshaller() {
try {
Marshaller marshaller = getJaxbContext().createMarshaller();
initJaxbMarshaller(marshaller);
return marshaller;
}
catch (JAXBException ex) {
throw convertJaxbException(ex);
}
}
Similar situation is by Unmarshaller.
Upvotes: 2
Reputation: 328546
Create several Jaxb2Marshaller
(say five), put them into a pool (use LinkedBlockingQueue
). When you create a thread, pass it the queue.
When a thread needs one, take()
one from the queue/pool. When the pool is empty, threads will block on this call.
When a thread is done using the Jaxb2Marshaller
, put()
it back into the queue so other threads can use it.
If you find that threads block too often waiting for a marshaller, add more to the queue (see the first step). That way, you can easily size the pool (or even make it configurable). The queue will then automatically distribute them.
Upvotes: 0
Reputation: 403441
The javadoc for Jaxb2Marshaller
makes no mention of thread-safety one way or another, so I'm not sure why you think it's not. If it wasn't thread-safe, the javadoc would say that very clearly.
Your configuration of WebServiceTemplate
, SaajSoapMessageFactory
and Jaxb2Marshaller
singletons is perfectly fine, and entirely thread-safe.
Upvotes: 7