JMS消息监听执行失败,没有设置ErrorHandler

Posted

技术标签:

【中文标题】JMS消息监听执行失败,没有设置ErrorHandler【英文标题】:Execution of JMS message listener failed, and no ErrorHandler has been set 【发布时间】:2012-02-13 21:42:01 【问题描述】:

当我使用 Spring 收听 JMS 消息时,我收到了上述错误。

我想知道如何将 Errorhandler 添加到 JMS 侦听器中?

【问题讨论】:

【参考方案1】:

AbstractMessageListenerContainer上有一个属性:

<bean id="listener" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="errorHandler" ref="someHandler"/>
    <property name="destinationName" value="someQueue"/>
    <property name="connectionFactory" ref="connectionFactory"/>
</bean>

其中someHandler 是实现ErrorHandler 的bean:

@Service
public class SomeHandler implements ErrorHandler 

    @Override
    public void handleError(Throwable t) 
        log.error("Error in listener", t);
    

但请注意,根据documentation:

此消息侦听器的默认行为 [...] 将在错误级别记录任何此类异常。 [...] 但是,如果需要错误处理,则可以将 ErrorHandler 策略的任何实现提供给 setErrorHandler(ErrorHandler) 方法。

看看你的日志,也许异常已经被记录了?

【讨论】:

看起来异常是默认使用 WARN 级别记录的。 @user705414:这似乎是文档中的一个错误:AbstractMessageListenerContainer.invokeErrorHandler() 确实使用了log.warn()。我使用@Service 来自动检测 bean,当然任何声明错误处理程序 bean 的方式都可以。【参考方案2】:

我喜欢它又短又甜!

    @Bean
JmsListenerContainerFactory<?> jmsContainerFactory(ConnectionFactory connectionFactory) 
    SimpleJmsListenerContainerFactory factory = new SimpleJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setErrorHandler(t -> 
         log.error("Error in listener!", t);
       );
    return factory;

【讨论】:

【参考方案3】:

没有xml配置。我在 ApplicationContext 中做了以下操作。

@Bean
JmsListenerContainerFactory<?> jmsContainerFactory(ConnectionFactory connectionFactory,
        SomeHandler errorHandler) 
    SimpleJmsListenerContainerFactory factory = new SimpleJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setErrorHandler(errorHandler);
    return factory;



// From Tomasz answer
@Service
public class SomeHandler implements ErrorHandler 

    @Override
    public void handleError(Throwable t) 
        log.error("Error in listener", t);
    

【讨论】:

【参考方案4】:

如果使用默认工厂:

    @Bean
    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory,
            SomeHandler errorHandler) 
        DefaultJmsListenerContainerFactory factory =
                new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setErrorHandler(errorHandler);
        return factory;
    

【讨论】:

【参考方案5】:

我检查了答案,但没有人告诉我们这个错误处理程序是什么以及为什么我们需要设置这个错误处理程序? JMSException 不需要此 errorHandler。 JMSException 需要被 exceptionListener 监听,如下所示

DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setExceptionListener(new ExceptionListener() 
            @Override
            public void onException(JMSException exception) 
                System.out.println("JMSException is occurred " + exception);
                //TODO the way you need to handle the exception
            
        );

这个 ErrorHandler 用于在处理消息时抛出任何未捕获的异常时调用。

默认情况下,不会有 ErrorHandler,因此错误级别的日志记录是唯一的结果。

 DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setErrorHandler(new ErrorHandler() 
            @Override
            public void handleError(Throwable t) 
                System.out.println("Unknown Exception is occurred " + t);
            
        );

这是最好的方法吗?

设置errorHandler是一种处理消息处理过程中发生的未知异常的方法。但是当我们看这个场景时,我们错过了 JMS 的实际消息。对于故障排除,消息将起到至关重要的作用。所以我的方法如下 在 JMSListener 方法中

 @JmsListener(destination = "$ibm.mq.queue.response.edmonton", containerFactory = "mqContainerFactory", concurrency = "$ibm.mq.concurrency")
    public void receiveMessage(Message message) 
     try
        //MessageProcessingCode
     catch(Exception ex)
       //Define a custom ErrorHandler which can take exception and message
       CustomErrorHandler eh = new CustomErrorHandler();
       eh.handleError(ex,message);
     
    

请注意,我们不会捕获 throwable,因为 Throwable 是 Java 中所有错误和异常的超类。错误是所有错误的超类,这些错误并不意味着被应用程序捕获。捕获 Throwable 或 Error 也会捕获 OutOfMemoryError 和 InternalError,应用程序不应尝试从中恢复。

【讨论】:

receiveMessage 函数中的 try catch 块没有捕捉到 JMS Listener 中抛出的异常

以上是关于JMS消息监听执行失败,没有设置ErrorHandler的主要内容,如果未能解决你的问题,请参考以下文章

Spring整合JMS——消息监听器

一个 JMS 消费者停止监听活动的 mq 主题,而第二个没有

如何使 JMS onMessage 方法异步

Spring + JMS + ActiveMQ实现简单的消息队列(监听器异步实现)

通过 Spring 集成入站适配器接收 JMS 消息随机失败

学习ActiveMQ:JMS消息的确认与重发机制