最后值队列是一种特殊的队列,当队列中放入具有相同最后值属性的新消息时,它会丢弃任何消息。换句话说,最后值队列只保留最后一个值。

最后值队列的一个典型例子是股票价格,您只关心特定股票的最新值。

发送到最后值队列而不指定属性的消息将像往常一样传递,并且永远不会被“替换”。

1. 配置

最后值键配置

最后值队列可以通过 broker.xml 中的 last-value-key 静态配置。

<address name="foo.bar">
   <multicast>
      <queue name="orders1" last-value-key="reuters_code" />
   </multicast>
</address>

在使用 CORE api 创建队列时指定,将参数 lastValue 设置为 true

或者,在使用 JMS 客户端时,在创建消费者使用的目标时使用地址参数进行自动创建。

Queue queue = session.createQueue("my.destination.name?last-value-key=reuters_code");
Topic topic = session.createTopic("my.destination.name?last-value-key=reuters_code");

可以使用地址通配符为一组地址配置最后值队列(参见 此处)。

<address-setting match="lastValueQueue">
   <default-last-value-key>reuters_code</default-last-value-key>
</address-setting>

默认情况下,default-last-value-keynull

传统最后值配置

最后值队列也可以通过 last-value 布尔属性配置,这样做会将 last-value-key 默认设置为 _AMQ_LVQ_NAME

<address name="foo.bar">
   <multicast>
      <queue name="orders1" last-value="true" />
   </multicast>
</address>

在使用 CORE api 创建队列时指定,将参数 lastValue 设置为 true

或者,在使用 JMS 客户端时,在创建消费者使用的目标时使用地址参数进行自动创建。

Queue queue = session.createQueue("my.destination.name?last-value=true");
Topic topic = session.createTopic("my.destination.name?last-value=true");

同样,所有队列在地址下的默认值可以使用 address-setting 配置

<address-setting match="lastValueQueue">
   <default-last-value-queue>true</default-last-value-queue>
</address-setting>

默认情况下,default-last-value-queue 为 false。

请注意,address-setting last-value-queue 配置已弃用,请改用 default-last-value-queue

2. 最后值属性

用于标识最后值的属性名称在上面提到的队列级别可配置。

如果使用传统设置配置 LVQ,则使用默认属性 "_AMQ_LVQ_NAME"(或 Core API 中的常量 Message.HDR_LAST_VALUE_NAME)。

例如,使用示例配置

<address name="foo.bar">
   <multicast>
      <queue name="orders1" last-value-key="reuters_code" />
   </multicast>
</address>

如果将两条具有相同最后值属性值的的消息发送到最后值队列,则队列中只会保留最新的消息。

// send 1st message with Last-Value property `reuters_code` set to `VOD`
TextMessage message = session.createTextMessage("1st message with Last-Value property set");
message.setStringProperty("reuters_code", "VOD");
producer.send(message);

// send 2nd message with Last-Value property `reuters_code` set to `VOD`
message = session.createTextMessage("2nd message with Last-Value property set");
message.setStringProperty("reuters_code", "VOD");
producer.send(message);

...

// only the 2nd message will be received: it is the latest with
// the Last-Value property set
TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
System.out.format("Received message: %s\n", messageReceived.getText());

3. 强制所有消费者为非破坏性

将最后值队列与 非破坏性 语义结合起来很常见。

4. 集群

最后值队列和集群背后的基本理念相互矛盾。

集群被设计为通过水平扩展来提高消息吞吐量。集群队列中的消息可以分布在集群中的所有节点上。这允许客户端分布在整个集群中,以利用所有节点的计算资源,而不是被单个节点瓶颈。

但是,如果您想在集群中使用最后值队列,那么为了强制执行最后值语义,所有消息都需要发送到单个节点上的队列。这将有效地抵消集群的好处。此外,到达其他节点的消息以及从其他节点重新分配的消息(而不是强制执行最后值语义的节点)几乎肯定会影响哪个消息被认为是“最后一个”。

出于这些原因,最后值队列在传统集群中不受支持。但是,可以在集群(甚至是一组非集群代理)前面使用 连接路由器 来确保所有需要使用相同最后值队列的客户端都被定向到同一个节点。有关配置等的更多详细信息,请参阅 连接路由器

5. 示例

参见 最后值队列示例,其中展示了最后值队列如何在 JMS 中配置和使用。