thread safety when using spring WebServiceTemplate and Jaxb2Marshaller
Asked Answered
M

3

7

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.

Measureless answered 13/8, 2010 at 15:49 Comment(0)
A
7

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.

Amalberga answered 14/8, 2010 at 11:4 Comment(7)
The definition of the createMarshaller() [static.springsource.org/spring-ws/sites/1.5/apidocs/org/… method sowed the seed of doubt in my mind. It says "JAXB marshallers are not necessarily thread safe." I know they are talking about javax.xml.bind.Marshaller but I am not sure how Jaxb2Marshaller uses this class(or implementations of this interface).Measureless
@neesh: Ah, OK. This is true, Marshaller and Unmarshaller objects are not thread-safe, that's why Spring-WS doesn't share them between threads. This is about correct use of the JAXB API.Amalberga
I had this issues some time ago where I needed to manually unmarshall using a singleton marshaller in a multi-threaded flow and it definitely misbehaved until I made sure each thread had it's own instance.Lemaceon
Why is this answer chosen as correct?? is it correct??Ivelisseivens
Spring Jaxb2Marshaller contains a singleton JAXBContext and creates a JAXB2Marshaller for each marshalling operation as suggested by JAXB. So Spring Jaxb2Marshaller has correct thread safety implementation.Report
Jaxb2Marshaller works well but is poorly named; it should probably be called something like Jaxb2MarshallerWrapper to indicate that it's not an actual JAXB Marshaller.Newfangled
Correct, let me add that a Jaxb2Marsaller implements the interface org.springframework.oxm.Marshaller, so the ambiguity comes from the name conflict of this interface with the javax.xml.bind.Marshaller that are created on each call to marshal()Naseberry
C
2

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.

Cirri answered 11/9, 2021 at 10:48 Comment(0)
L
0

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.

Licastro answered 13/8, 2010 at 15:52 Comment(1)
This will work, and the pool idea is widely used with objects that are heavy to instantiate, but then you will have to manage the objects state and so on, such is done in connection pool. But Marshaller is not a heavy object to instantiate. JaxbContext is.Ivelisseivens

© 2022 - 2024 — McMap. All rights reserved.