尝试使用 Spring Boot 使用 JMS 主题消息时出现异常

Posted

技术标签:

【中文标题】尝试使用 Spring Boot 使用 JMS 主题消息时出现异常【英文标题】:Exception while trying to consume a JMS Topic message using Spring Boot 【发布时间】:2020-07-20 19:54:42 【问题描述】:

我正在尝试使用来自 ActiveMQ 主题的消息。下面是代码:

@Configuration
@EnableJms
public class Config 

@Value("$activemq.broker-url")
private String brokerURL;

@Bean
public ActiveMQConnectionFactory activeMQConnectionFactory() 
    ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
    activeMQConnectionFactory.setBrokerURL(brokerURL);
    activeMQConnectionFactory.setTrustAllPackages(true);
    return activeMQConnectionFactory;


public DefaultJmsListenerContainerFactory jmsListenerContainerFactory()
    DefaultJmsListenerContainerFactory defaultJmsListenerContainerFactory = new DefaultJmsListenerContainerFactory();
    defaultJmsListenerContainerFactory.setConnectionFactory(activeMQConnectionFactory());
    defaultJmsListenerContainerFactory.setPubSubDomain(true);
    return defaultJmsListenerContainerFactory;

我的消费者代码:

@Component
@EnableJms
public class Consumer 

   @JmsListener(destination = "xml.inbound.topic", containerFactory = "jmsListenerContainerFactory")
   public void Processor(final Message xmlMessage) 

   

我得到的例外是:

通过字段 'jmsTemplate' 表达的不满足的依赖关系;嵌套异常是 org.springframework.beans.factory.BeanCreationException:在类路径资源 [com/investmentbank/equityfeedsprocessingrevised/config/Config.class] 中定义名称为“jmsTemplate”的 bean 创建时出错:通过工厂方法进行 bean 实例化失败;嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 [org.springframework.jms.core.JmsTemplate]:工厂方法“jmsTemplate”抛出异常;嵌套异常是 java.lang.ClassCastException:类 org.springframework.jms.config.DefaultJmsListenerContainerFactory 无法转换为类 javax.jms.ConnectionFactory(org.springframework.jms.config.DefaultJmsListenerContainerFactory 和 javax.jms.ConnectionFactory 位于未命名的模块中加载程序“应用程序”)

我在这里做错了什么?为什么会出现异常?

我也试过了:

@Bean
public DefaultMessageListenerContainer jmsListenerContainerFactory() 
        DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
        dmlc.setConnectionFactory(activeMQConnectionFactory());
        dmlc.setPubSubDomain(true);
        return dmlc;

我在这里得到的例外是:

通过字段 'jmsTemplate' 表达的不满足的依赖关系;嵌套异常是 org.springframework.beans.factory.BeanCreationException:在类路径资源 [com/investmentbank/equityfeedsprocessingrevised/config/Config.class] 中定义名称为“jmsTemplate”的 bean 创建时出错:通过工厂方法进行 bean 实例化失败;嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 [org.springframework.jms.core.JmsTemplate]:工厂方法“jmsTemplate”抛出异常;嵌套异常是 org.springframework.beans.factory.BeanCreationException:在类路径资源 [com/investmentbank/equityfeedsprocessingrevised/config/Config.class] 中定义名称为“jmsListenerContainerFactory”的 bean 创建错误:调用 init 方法失败;嵌套异常是 java.lang.IllegalArgumentException:需要属性“destination”或“destinationName”

只需添加我的 JmsTemplate 代码如下所示:

@Bean
public JmsTemplate jmsTemplate() 
JmsTemplate jmsTemplate = new JmsTemplate();
         jmsTemplate.setConnectionFactory(activeMQConnectionFactory());
         jmsTemplate.setPubSubDomain(true);
         return jmsTemplate;

我已经使用 Apache Camel(代码)实现了 JMS 主题发布器:

ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
        CamelContext _ctx = new DefaultCamelContext(); 
        _ctx.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
        _ctx.addRoutes(new RouteBuilder() 

            public void configure() throws Exception 
                from("file:src/main/resources?fileName=data-sample_2.csv")
                .process(new MyTransformRevised1())
                .to("file:src/main/resources/?fileName=emp.xml")                
                .split(body().tokenizeXML("equityFeeds", null)).streaming().to("jms:topic:xml.inbound.topic");
            

        );

我可以在我的主题名称的“消息入队”列中看到消息的数量。

出了什么问题?我在网上阅读了各种帖子,但无法解决问题。请帮助解决问题。我无法阅读有关 ActiveMQ 主题的消息。让我知道我是否缺少某些信息。

【问题讨论】:

【参考方案1】:

我用下面的代码解决了这个问题:

    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory()
    DefaultJmsListenerContainerFactory defaultJmsListenerContainerFactory = new DefaultJmsListenerContainerFactory();
                defaultJmsListenerContainerFactory.setConnectionFactory(activeMQConnectionFactory());
defaultJmsListenerContainerFactory.setPubSubDomain(true);
return defaultJmsListenerContainerFactory;
        

     @Bean
     public JmsTemplate jmsTemplate() 
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setConnectionFactory(activeMQConnectionFactory());
        jmsTemplate.setPubSubDomain(true);
        return jmsTemplate;
    

    @JmsListener(destination = "$my.inboundTopicName", containerFactory = "jmsListenerContainerFactory")
    public void myProcessor(final Message xmlMessage) 
    ///

    

我想补充一点,我遇到了一些不寻常的行为。

    消息从生产者生成的时间,如果 消费者已启动,然后只有消息被消费者消费 消费者。我的意思是如果消息是由生产者产生的 并被 ActiveMQ 排队,一段时间后我打开了消费者 那么消息不会被消费者消费。

    。消息被消费之前也需要一段时间 消费者。

【讨论】:

【参考方案2】:

您可以尝试将activeMQConnectionFactory 包装在CachingConnectionFactory 中并利用DefaultJmsListenerContainerFactoryConfigurer 来配置JmsListenerContainerFactory

@Bean
ConnectionFactory connectionFactory() 
    return new CachingConnectionFactory(activeMQConnectionFactory());


@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactory(ConnectionFactory connectionFactory,
                                    DefaultJmsListenerContainerFactoryConfigurer configurer) 

    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    return factory;

编辑开始:

您可以尝试将JmsTemplate 更改为:

@Bean
public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) 
JmsTemplate jmsTemplate = new JmsTemplate();
         jmsTemplate.setConnectionFactory(connectionFactory);
         jmsTemplate.setPubSubDomain(true);
         return jmsTemplate;

【讨论】:

刚刚试过上面的。我只是在上面的代码中再添加了一行,即factory.setPubSubDomain(true);configurer.configure(factory, connectionFactory); 之前和之后都尝试了两种方法,但仍然没有工作。没有异常,但也没有输出。它还没有准备好以某种方式收听主题。我真的不知道该如何解决这个问题。 将消息发送到主题的代码看起来如何?您可以尝试删除 ConnectinFactory bean,因为 Spring Boot 应该已经为您做到了? 我已经使用 Apache Camel 实现了 JMS Publisher。在上面编辑了我的问题以添加相同的代码。我还想补充一点,当我使用队列时,它工作得非常好,但使用 Topic 没有任何效果。 如果使用jmsTemplate直接给topic发送Message有什么变化吗? 没试过。如上所述,我已经使用 Apache Camel 实现了我的发布者,并且它根据 ActiveMQ 中的主题名称之外的“消息入队”编号成功地将消息发送到 ApacheMQ。此外,Apache Camel 与 Queues 完美配合,我的 JmsConsumer 与 Apache Camel 作为“发布者”和我的 JmsListener 作为“消费者”也完美配合。所以我不认为 Apache Camel 作为“发布者”在这里应该是一个问题。

以上是关于尝试使用 Spring Boot 使用 JMS 主题消息时出现异常的主要内容,如果未能解决你的问题,请参考以下文章

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

如何在spring boot中实现jms队列

Spring Boot 中 JMS 消费者的动态缩放

ActiveMQ rebalanceClusterClients 不适用于 Spring Boot JMS

带有 tibco jms 监听器的 Spring Boot

Spring-boot JMS 发送消息慢的问题解决