jms持久消息和获得的消息顺序

时间:2013-09-11 08:53:13

标签: spring jms activemq

我需要什么:  1.通过jms发送消息。  2.保留消息,以便在未从客户端和服务器重新启动时处理客户端在服务器重新启动时获取消息。  3.应以与发送这些消息相同的顺序从客户端接收消息。  4.队列中有多个消费者,以便并行扩展和处理不同的消息。

我做了什么: 我使用有源mq并具有以下弹簧配置

<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg index="0" value="destination"/>
</bean>

<bean id="template" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="pooledConnectionFactory"/>
    <property name="deliveryMode" value="2"/>
    <property name="defaultDestination" ref="destination"/>
</bean>

<bean id="messageListener" class="InternalNotificationJMSConsumer"/>

<jms:listener-container connection-factory="pooledConnectionFactory" acknowledge="client" destination-type="queue" concurrency="5-10" container-type="simple"  cache="none" client-id="client1" prefetch="1">
      <jms:listener destination="destination" ref="messageListener" method="onMessage"/>
</jms:listener-container>

所以我有我的目的地和我的连接池。然后我创建一个spring jmstemplate并开始发送消息

template.send(new MessageCreator() {
  public Message createMessage(Session session) throws JMSException {
    return session.createObjectMessage(message);
  }
});

然后我有接收器如下:

@Component
public class JMSConsumer implements MessageListener {

  @Override
  public void onMessage(Message message) {
    if (message instanceof ObjectMessage) {
      ....
     }
   }

我的问题:

一个。不按顺序接收使用此配置的消息。这使得在listener-container.concurency中给出了xsd注释:“如果是主题监听器,或者如果消息排序很重要,则将并发限制为1;”。所以问题是如何/如果我可以保持秩序但有多个消费者。

湾消息确认。我需要的是,在处理完消息后,onMessage返回,只有消息被认为是已确认且未被重新传输。我没有任何事务管理员,我不在任何应用程序服务器内,并希望尽可能避免这种情况。我只需要承认自己的信息。这可能吗?

2 个答案:

答案 0 :(得分:1)

如果您正在并行消费消息,那么由于线程的性质,永远无法保证它们将按照发送的顺序完成 - 只是它们将按顺序传递给消费者。如果只有某些消息绝对必须被排序(通常与交易/帐户相关),您可以使用Message Groups功能将群组与消费者相关联 - 这是一种粘性负载平衡。

自己确认消息绝对是可能的,但可能不需要。 MessageListenerContainer具有acknowledge属性,如果设置为transacted,则只有在MessageListener完成执行后才会将消息确认为已消耗,而不会抛出异常。没有必要的事务管理器(尽管Spring的PlatformTransactionManager不需要任何特定的容器,如果你确实想要使用它)。

如果您确实要自己确认消息,请将acknowledge设置为client,并在消息成功完成后致电message.acknowledge()。如果侦听器在没有调用的情况下完成,则消息将被发送到DLQ(默认)或重新传送。

答案 1 :(得分:1)

好的,这是我的问题的答案。

<jms:listener-container connection-factory="pooledConnectionFactory" acknowledge="client" destination-type="queue" concurrency="5-10" container-type="simple"  cache="none" prefetch="1">
      <jms:listener destination="destination" ref="messageListener" method="onMessage"/>
</jms:listener-container>

然后在消息监听器实现上: BlockingExecutor executor = new BlockingExecutor(5); //要消耗的连续按摩次数

public void onMessage(Message message) {
....
executor.submitTask(new MessageDispatchCommand((ObjectMessage) message));
....

}

class MessageDispatchCommand implements Runnable {
  private ObjectMessage message;

  public MessageDispatchCommand (final ObjectMessage message) {
    this.message = message;
  }

  public void run() {
    try {
      Serializable msg = message.getObject();
      handle message here
     }....
}

可以在此处找到BlockingExecutor代码:     Java Concurrency in Practice: BoundedExecutor implementation

简单地说。我只有一个jms消息监听器,因为这可以保持消息顺序正确。 然后我创建runnable命令来获取消息并处理它们(这是耗时的工作,但它是在不同的线程内完成的)。 由于我在所有消息处理线程都被使用时使用了boundedexecutor,因此onMessage阻塞,因此后续消息只是持久化,直到有界执行程序的线程再次空闲。