JMS-一个队列和多个接收器(使用者)

JMS-一个队列和多个接收器(使用者),jms,consumer,Jms,Consumer,我有一个由第三方发布的JMS队列。 我想在不同的机器上设置多个消费者,只有一个特定机器的消费者,确认该队列上的消息。简言之,如果特定计算机的使用者未收到该消息,则不应从队列中删除该消息。 这是可以实现的吗 好的,您可能有自己的理由进行此设置,而且很容易实现 我将使用本地会话事务。根据某些标准(例如哪个服务器正在使用消息)提交或回滚事务相当容易。如果回滚,消息将再次在队列中首先结束 示例代码可能如下所示: public class MyConsumer implements MessageList

我有一个由第三方发布的JMS队列。 我想在不同的机器上设置多个消费者,只有一个特定机器的消费者,确认该队列上的消息。简言之,如果特定计算机的使用者未收到该消息,则不应从队列中删除该消息。
这是可以实现的吗

好的,您可能有自己的理由进行此设置,而且很容易实现

我将使用本地会话事务。根据某些标准(例如哪个服务器正在使用消息)提交或回滚事务相当容易。如果回滚,消息将再次在队列中首先结束

示例代码可能如下所示:

public class MyConsumer implements MessageListener{ 
  Session sess;

  public void init(Connection conn, Destination dest){
    // connection and destination from JNDI, or some other method.
    sess = conn.createSession(true, Session.AUTO_ACKNOWLEDGE);
    MessageConsumer cons = sess.createConsumer(dest);
    cons.setMessageListener(this);
    conn.start();
  }

  @Override
  public void onMessage(Message msg) {
    // Do whatever with message
    if(isThisTheSpecialServer()){
       sess.commit();
    }else{
       sess.rollback();
    }
   }

   private boolean isThisTheSpecialServer(){
      // figure out if this server should delete messages or not
   }
}
如果您使用JTA在JavaEE容器中执行此操作,并且您使用的是UserTransactions,那么您可以调用UserTransaction.setRollBack(); 或者,如果您使用的是声明性事务,您可以在读取消息并完成操作后,抛出运行时异常以使事务失败并将消息回滚到队列中。注意,这种方法也会回滚数据库更改(如果您使用的是JTA而不是本地JMS事务)

更新:

您确实应该使用事务来完成这项工作,而不是使用确认

这里可以找到本主题的摘要(针对ActiveMQ,但通常是为JMS编写的)。

我不知道这种行为是否与所有JMS实现一致,但对于ActiveMQ,如果您尝试使用带有session.CLIENT_确认的非事务会话,那么它将不会真正像您所期望的那样工作。已读取但未确认的消息仍在队列中,但在与第一个使用者的连接断开(即connection.close()、崩溃或类似情况)之前,不会被“释放”并传递给其他JMS使用者


通过使用本地事务,您可以显式地通过session.commit()和session.rollback()控制此操作。我认为不使用事务没有任何实际意义。确认只是为了保证交付。

另一种方法是在转发队列的情况下。您可以通过执行以下操作将其应用于您的设计:

  • 从第三方在已发布队列上创建使用者
  • 此使用者有一个作业-将每条消息分发到其他队列
  • 创建真实订阅者将侦听的其他队列
  • 对消息侦听器进行编码,以接收每条消息并将其转发到各个目的地
  • 将每个侦听器更改为从其特定队列中读取

  • 通过这样做,您可以确保每个侦听器都能看到每一条消息,每一个事务都按预期工作,并且您不会对消息的发送方式做出任何假设(例如,如果发布方正在执行
    自动确认
    ?)

    不知道是什么原因,我认为所有消费者都必须收到一条消息,但只有一个特定的消费者会确认该消息。如果不是这样,为什么您希望同一队列有多个使用者?仅供参考:回滚将增加JMSXDeliveryCount。JMS队列配置为在JMSXDeliveryCount达到阈值后将消息移动到回退队列。在此处使用事务对您没有任何帮助,只能确保您从端到端加入JTA事务。当然,但可能可以配置回退阈值(取决于供应商)。当然,如果您回滚事务并且没有回退队列接收消息,那么其他消费者将可以使用它。当然,最好对消息进行适当的路由,但我在这里看不到完整的情况。