首页 > 解决方案 > Java JMS - 消息侦听器和 onException

问题描述

我有一个带有主线程和 JMS 线程的应用程序,它们通过 ActiveMQ 5.15.11 相互通信。我可以很好地发送消息,但是我想要一种发回状态或错误的方法。我注意到MessageListener允许onSuccess()onException(ex)作为两个事件来监听,但是我发现只有onSuccess()被调用。

这是我的代码片段。

JMS 线程:

ConnectionFactory factory = super.getConnectionFactory();
Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(super.getQueue());
MessageConsumer consumer = session.createConsumer(queue);
consumer.setMessageListener(m -> {
   try {
      super.processRmbnConfigMsg(m);
   } catch (JMSException | IOException e) {
      LOG.error(e.getMessage(), e);

      // I can only use RuntimeException. 
      // Also this exception is what I am expecting to get passed to the onException(..)
      // call in the main thread.
      throw new RuntimeException(e);
   }
});
connection.start();

主线程(向 JMS 发送消息):

sendMessage(xml, new AsyncCallback() {
    @Override
    public void onException(JMSException e) {
        // I am expecting this to be that RuntimeException from the JMS thread.
        LOG.error("Error", e);
        doSomethingWithException(e);
    }

    @Override
    public void onSuccess() {
        LOG.info("Success");
    }
});

我所期望的是,即使被包装new RuntimeException(e)了,事件侦听器也会以某种方式接收到抛出的异常。onException(JMSException e)RuntimeException

相反,我总是收到onSuccess()事件。我想该onException(..)事件是在通信问题期间发生的,但我想要一种将异常发送回给调用者的方法。

如何实现在 JMS 线程中收集错误并将其发送回调用线程的目标?

标签: javajmsactivemq

解决方案


您的期望是基于对 JMS 的根本误解。

代理消息传递的基本原则之一是生产者和消费者在逻辑上彼此断开连接。换句话说……生产者向代理发送消息,它不一定关心它是否消费成功,它当然不会知道是消费它,也不知道什么时候会被消费。同样,消费者不一定知道消息何时发送、为何发送或是谁发送的。这在生产者和消费者之间提供了极大的灵活性。JMS 遵循断开生产者和消费者的这一原则。

消费者没有直接的方法来通知生产者关于它发送的消息的消费问题。也就是说,您可以使用所谓的“请求/响应模式”,以便消费者可以向生产者提供某种反馈。您可以在此处找到此模式的说明以及示例代码。

此外,AsyncCallback您使用的类不是 JMS 的一部分。我相信它是org.apache.activemq.AsyncCallback由 ActiveMQ 本身专门提供的,它只为实际发送操作的成功或失败提供回调(即不用于消息的消费)。

最后,您应该知道,RuntimeException从 a 的onMessage方法中抛出 ajavax.jms.MessageListener被 JMS 规范视为“编程错误”,应该避免。JMS 2 规范的第 8.7 节规定:

侦听器可以抛出RuntimeException; 但是,这被认为是客户端编程错误。表现良好的侦听器应捕获此类异常并尝试将导致它们的消息转移到某种形式的特定于应用程序的“无法处理的消息”目的地。监听器抛出 a 的结果RuntimeException取决于会话的确认模式。

  • AUTO_ACKNOWLEDGEDUPS_OK_ACKNOWLEDGE- 消息将立即重新传递。JMS 提供者在放弃之前重新传递相同消息的次数取决于提供者。对于在这些情况下重新传递的消息,将设置 JMSRedelivered 消息头字段,并增加 JMSXDeliveryCount 消息属性。

  • CLIENT_ACKNOWLEDGE- 为侦听器传递下一条消息。如果客户端希望重新传递先前未确认的消息,它必须手动恢复会话。

  • Transacted Session - 传递给监听器的下一条消息。客户端可以提交或回滚会话(换句话说,aRuntimeException不会自动回滚会话)。


推荐阅读