1
votes

We are rewriting a J2EE-based service that runs on Websphere AS, now using Spring 5.1/Spring Boot 2.1 with Tomcat as target platform. The service gets its requests via IBM MQ (with a fixed number of request queues for different clients) and sends the responses using corresponding response queues.

One important part of the J2EE implementation is that for each input queue there is a configurable number of MDBs which process the requests in parallel (which corresponds to the client-specific number of connections to the backend system used for processing).

In our new Spring implementation, we use one DefaultJmsListenerContainerFactory and several @Component classes, each with a @JmsListener annotated method. Everything works fine as long as we confine ourselves to sequential message processing: Concurency is 1, and the singleton beans process one message after the other.

If we raise the concurrency value, we get the expected trouble: Since our singleton listener beans are not thread-safe, the parallel processing of messages produces chaos. We thought the easiest solution would be to use multiple instances of each listener bean (like we did with the MDBs in J2EE), so we annotated the listener bean classes with @Scope("prototype").

The result was frustrating: There was no more message processing at all! In the log file, we can only see "Creating shared instance of singleton bean ..." (why singleton??) but neither any log output from the constructor nor an error message, so it's clear that the listener beans were not properly instantiated. We then tried SimpleThreadScope instead of prototype scope, but despite proper registration this resulted in the same problem.

I tried to check whether this problem has occured anywhere else and found only one case (https://github.com/spring-projects/spring-framework/issues/18045), but the unresolved issue was closed for unknown reasons.

Is this a bug or am I too optimistic to demand multiple instances of a listener bean by changing the @Scope?

1

1 Answers

1
votes

There was no more message processing at all!

You need to call applicationContext.getBean("myBeanWithAJmsListener") n times to create n instances of your listener. Do this after the context has initialized; e.g. in an ApplicationRunner if you are using Spring Boot.

Prototype-scoped beans are not automatically instantiated.

You are responsible for destroy() ing the instances during shutdown.

See this answer for an example - in that case each instance listens to a different queue.