如何使 Jms Listener Bean 成为非单例?

How to make a Jms Listener Bean a non-singleton?

我们正在重写在 Websphere AS 上运行的基于 J2EE 的服务,现在使用 Spring 5.1/Spring Boot 2.1 和 Tomcat 作为目标平台。该服务通过 IBM MQ(针对不同客户端具有固定数量的请求队列)获取其请求,并使用相应的响应队列发送响应。

J2EE 实现的一个重要部分是,对于每个输入队列,都有可配置数量的 MDB,它们并行处理请求(这对应于用于处理的后端系统的客户端特定连接数) .

在我们新的 Spring 实现中,我们使用一个 DefaultJmsListenerContainerFactory 和几个 @Component 类,每个都有一个 @JmsListener 注释方法。只要我们将自己限制在顺序消息处理中,一切都可以正常工作:并发性为 1,单例 bean 一个接一个地处理消息。

如果我们提高并发值,就会遇到预期的麻烦:由于我们的单例侦听器 bean 不是线程安全的,因此消息的并行处理会产生混乱。我们认为最简单的解决方案是使用每个侦听器 bean 的多个实例(就像我们在 J2EE 中对 MDB 所做的那样),所以我们用 @Scope("prototype").[= 注释侦听器 bean 类。 11=]

结果令人沮丧:根本没有更多的消息处理!在日志文件中,我们只能看到 "Creating shared instance of singleton bean ..."(为什么是单例??),但既没有构造函数的任何日志输出,也没有错误消息,因此很明显监听器 bean 没有正确实例化。然后我们尝试了 SimpleThreadScope 而不是原型作用域,但是尽管注册正确,这导致了同样的问题。

我试图检查这个问题是否在其他地方发生过,只发现了一个案例(https://github.com/spring-projects/spring-framework/issues/18045),但未解决的问题因未知原因被关闭。

这是一个错误还是我过于乐观以至于无法通过更改@Scope 来要求一个侦听器 bean 的多个实例?

There was no more message processing at all!

您需要调用 applicationContext.getBean("myBeanWithAJmsListener") n 次才能创建 n 个侦听器实例。在上下文初始化后执行此操作;例如在 ApplicationRunner 如果您使用 Spring Boot.

原型范围的 bean 不会自动实例化。

您有责任在关闭期间 destroy() 访问实例。

请参阅 示例 - 在这种情况下,每个实例都会侦听不同的队列。