JMS - 一个队列和许多接收者(消费者)

时间:2012-07-15 01:48:28

标签: jms consumer

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

2 个答案:

答案 0 :(得分:1)

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

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

示例代码可能如下所示:

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的Java EE容器中执行此操作并且您正在使用UserTransactions,则可以只调用UserTransaction.setRollBack(); 或者,如果您正在使用声明性事务,则只需抛出一个运行时异常即可使事务失败,并在您阅读完消息并完成操作后将消息回滚到队列中。请注意,使用此方法也会回滚数据库更改(如果您使用的是JTA而非本地JMS事务)。

更新:

你应该使用交易而不是确认来做到这一点。

此主题的摘要(适用于ActiveMQ,但通常为JMS编写)可在此处找到。 http://activemq.apache.org/should-i-use-transactions.html

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

使用本地事务,您可以通过session.commit()和session.rollback()显式地控制它。我认为不使用交易没有实际意义。致谢就是保证交付。

答案 1 :(得分:0)

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

  1. 在第三方发布的队列中创建使用者。
  2. 此消费者有一项工作 - 将每条消息分发给其他队列。
  3. 创建真实订阅者将收听的其他队列。
  4. 对您的消息监听器进行编码,以获取每条消息并将其转发到各个目的地。
  5. 将每个侦听器更改为从特定队列中读取。
  6. 通过执行此操作,您可以确保每个侦听器都能看到每条消息,每个事务都按预期工作,并且您不会对消息的发送方式做出任何假设(例如,如果发布方正在执行该操作{{ 1}}?)

相关问题