为什么jmslisteners不能共享一个公共jms连接?

p4tfgftt  于 2021-07-26  发布在  Java
关注(0)|答案(1)|浏览(434)

我这样创建一个消息处理程序:

@JmsListeners(
  JmsListener(destination = "queue1"),
  JmsListener(destination = "queue2"),
  JmsListener(destination = "queue3"),
  JmsListener(destination = "queue4")
)
fun handleMessage(message: String) {
  // handle a message
}

当我检查我的消息代理时,我看到我的应用程序建立了4个连接。不幸的是,我对来自mq管理员的连接数量有限制,所以我希望消息处理程序只使用一个连接。
在检查了springjms的内部结构之后,我发现 DefaultMessageListenerContainer 能够使用共享连接。但问题是Spring DefaultMessageListenerContainerFactory 创建单独的 DefaultMessageListenerContainer 对于每个 @JmsListener .
同时,jmsapi允许创建多个 JMSConsumer 她是单身汉 JMSContext ,例如。

val jmsContext = connectionFactory.createContext(Session.SESSION_TRANSACTED)
val consumer1 = jmsContext.createConsumer(jmsContext.createQueue("queue1"))
val consumer2 = jmsContext.createConsumer(jmsContext.createQueue("queue2"))

我如何设置 JmsListener 共享公共连接?如果这是不可能的,Spring有一个合理的理由吗?

1dkrff03

1dkrff031#

我想发表评论,但我也需要显示代码,所以作为一个妥协。。。
我想你已经这样做了。这就像剥洋葱皮。
看起来似乎无法通过 application.properties - https://docs.spring.io/spring-boot/docs/2.4.1/reference/htmlsingle/#common-应用程序属性集成
也不能直接在代码中设置,但可能有一种方法可以影响它。使用以下一种或多种机制。
对于侦听器,必须指定容器工厂。顺便说一句,我不喜欢硬编码字符串,所以 application.properties 有一个 my.queue.name1 财产。

import org.springframework.jms.annotation.JmsListener;
    ...

    // Set upper concurrency limit on listener
    @JmsListener(destination = "${my.queue.name1}", containerFactory = "myListenerFactory", concurrency = "2")
    ...

退一步说,您将需要一个定制工厂的bean,在那里您可以控制如何创建连接。有可能 @Override 这个 createContainerInstance 方法,但是 DefaultMessageListenerContainer::sharedConnectionEnabled 方法是受保护的、最终的,因此不可能调用或重写。因此,您需要使用其他方法来限制可用的连接数。。。

import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
...    

    @Bean("myListenerFactory")
    public DefaultJmsListenerContainerFactory myCustomisedListenerFactory() {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory() {
            @Override
            protected DefaultMessageListenerContainer createContainerInstance() {
                DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();

                // This may the way to control how many concurrent consumers are created
                dmlc.setMaxConcurrentConsumers(2);
                return dmlc;
            }
        };
        factory.setConnectionFactory(connectionFactory);

        // Set the concurrency lower limit to upper limit
        factory.setConcurrency("1-2");

        // Plus any other customisations
        ...

        return factory;
    }

你的自动连线工厂。

import import javax.jms.ConnectionFactory;
...

    @Autowired
    private ConnectionFactory connectionFactory;

相关问题