Spring 4.1 @JmsListener 配置

Posted

技术标签:

【中文标题】Spring 4.1 @JmsListener 配置【英文标题】:Spring 4.1 @JmsListener configuration 【发布时间】:2014-11-12 01:01:42 【问题描述】:

我想将 Spring 4.1 中提供的新注释和特性用于需要 JMS 侦听器的应用程序。

我已经仔细阅读了Spring 4.1 JMS improvements post 中的注释,但我仍然想念@JmsListenerDestinationResolver 之间的关系,以及我将如何设置应用程序以指示正确的DestinationEndpoint .

这是@JmsListener 的建议用法

@Component
public class MyService 

    @JmsListener(containerFactory = "myContainerFactory", destination = "myQueue")
    public void processOrder(String data)  ... 

现在,我不能在我的实际代码中使用它,因为需要使用 Environment.getProperty() 从配置文件中读取“myQueue”。

我可以使用DestinationResolver 设置一个适当的 myContainerFactory,但大多数情况下,如果您不需要 JNDI 在应用服务器中查找队列并且不需要做一些自定义,您似乎只需使用DynamicDestinationResolver回复逻辑。我只是想了解 Spring 如何让我使用 @JmsListener 注释以参数化方式指示队列的名称。

在博客文章的后面,我找到了对这个配置器的引用:

@Configuration
@EnableJms
public class AppConfig implements JmsListenerConfigurer 

@Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) 
    registrar.setDefaultContainerFactory(defaultContainerFactory());

    SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
    endpoint.setDestination("anotherQueue");
    endpoint.setMessageListener(message -> 
        // processing
    );
    registrar.registerEndpoint(endpoint);

现在,这有点道理,我可以看到这将允许我在运行时从一些外部字符串设置目标,但这似乎与使用 @JmsListener 冲突,因为它似乎覆盖了在上面的代码中注释有利于endpoint.setMessageListener

关于如何使用@JmsListener 指定适当队列名称的任何提示?

【问题讨论】:

使用占位符。 destination="$name.of.your.property". 我宁愿不使用PropertyPlaceHolderConfiguration 来支持Environment.getProperty,但显然我不能将该路由作为注释的参数。 实际上,您将使用PropertySourcePlaceHolderConfigurer,它与Environment.getProperty 的作用基本相同(它会咨询所有PropertySources。您能否详细说明为什么您更喜欢Environment.getProperty 而不是占位符这个案子? 为什么@PropertySource 不能与占位符一起使用?它的工作原理相同。唯一的区别是您需要使用PropertySourcesPlaceHolderConfigurer。因此,使用占位符这一事实并不意味着您不能再使用@PropertySource 我在这里与@M.Deinum +1,并有兴趣了解使用占位符的问题。 【参考方案1】:

另请注意,根据用例,您已经可以使用每个环境的属性文件和 PropertySourcesPlaceholderConfigurer 进行参数化

@JmsListener(destinations = "$some.key")

根据https://jira.spring.io/browse/SPR-12289

【讨论】:

这正是我所追求的。 @Value 注释演示了模板化,但文档中没有明确说明它更普遍可用。谢谢!【参考方案2】:

如果人们将 @JmsListener 与 spring boot 一起使用,则不必配置 PropertySourcesPlaceholderConfigurer。开箱即用

示例:

@JmsListener(destination = "$spring.activemq.queue.name")
    public void receiveEntityMessage(final TextMessage message) 
    // process stuff 


application.properties

spring.activemq.queue.name=some.weird.queue.name.that.does.not.exist

Spring 启动输出

[26-Aug;15:07:53.475]-[INFO ]-[,]-[DefaultMes]-[o.s.j.l.DefaultMessageListenerContainer ]-[931 ]-Successfully refreshed JMS Connection 
[26-Aug;15:07:58.589]-[WARN ]-[,]-[DefaultMes]-[o.s.j.l.DefaultMessageListenerContainer ]-[880 ]-Setup of JMS message listener invoker failed for destination 'some.weird.queue.name.that.does.not.exist' - trying to recover. Cause: User user is not authorized to read from some.weird.queue.name.that.does.not.exist 
[26-Aug;15:07:59.787]-[INFO ]-[,]-[DefaultMes]-[o.s.j.l.DefaultMessageListenerContainer ]-[931 ]-Successfully refreshed JMS Connection 
[26-Aug;15:08:04.881]-[WARN ]-[,]-[DefaultMes]-[o.s.j.l.DefaultMessageListenerContainer ]-[880 ]-Setup of JMS message listener invoker failed for destination 'some.weird.queue.name.that.does.not.exist' - trying to recover. Cause: User user is not authorized to read from some.weird.queue.name.that.does.not.exist 

这证明@JmsListener 能够从 application.properties 中获取属性值,而无需实际设置任何显式 PropertySourcesPlaceholderConfigurer

我希望这会有所帮助!

【讨论】:

【参考方案3】:

您现在最终可以做到这一点,但这有点令人费解。您可以使用JmsListenerConfigurer 设置自定义JmsListenerEndpointRegistry

@Configuration
@EnableJms
public class AppConfig implements JmsListenerConfigurer 

    @Override
    public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) 
        registrar.setEndpointRegistry(customRegistry());
    


然后重写 registerListenerContainer 方法,类似于

public void registerListenerContainer(JmsListenerEndpoint endpoint, JmsListenerContainerFactory<?> factory) 
    // resolve destination according to whatever -> resolvedDestination
    ((AbstractJmsListenerEndpoint)endpoint).setDestination(resolvedDestination);
    super.registerListenerContainer(endpoint, factory);

但我们可以做得更好。请关注/投票给SPR-12280

【讨论】:

这个有更新吗?票似乎已被拒绝,但现在已经 5 年了

以上是关于Spring 4.1 @JmsListener 配置的主要内容,如果未能解决你的问题,请参考以下文章

如何在启动时以编程方式禁用 Spring @JmsListener

如何访问@JmsListener使用的Spring Boot中的活动JMS连接/会话

如何等待@JMSListener注释方法在JUnit中完成

我怎样才能停止/启动/暂停@JmsListener(干净的方式)

Spring Boot JMS 侦听器:无法刷新目标的 JMS 连接

如何使用@JmsListener 暂停并开始使用消息