註解驅動的監聽器端點

接收訊息最簡單的方式是使用註解驅動的監聽器端點基礎設施。簡單來說,它允許你將託管 bean 的方法暴露為 Rabbit 監聽器端點。以下示例展示瞭如何使用 `@RabbitListener` 註解

@Component
public class MyService {

    @RabbitListener(queues = "myQueue")
    public void processOrder(String data) {
        ...
    }

}

前面示例的思路是,只要 `myQueue` 佇列中有訊息可用,就會相應地呼叫 `processOrder` 方法(在此例中,使用訊息負載作為引數)。

註解端點基礎設施會為每個註解方法在後臺建立一個訊息監聽器容器,透過使用 `RabbitListenerContainerFactory` 實現。

在前面的示例中,`myQueue` 必須已經存在並繫結到某個交換器。只要應用上下文中存在 `RabbitAdmin`,該佇列就可以自動宣告和繫結。

註解屬性(如 `queues` 等)可以指定屬性佔位符 (`${some.property}`) 或 SpEL 表示式 (`#{someExpression}`)。請參閱監聽多個佇列,瞭解為何可能使用 SpEL 而非屬性佔位符的示例。以下列表展示了三種宣告 Rabbit 監聽器的方法
@Component
public class MyService {

  @RabbitListener(bindings = @QueueBinding(
        value = @Queue(value = "myQueue", durable = "true"),
        exchange = @Exchange(value = "auto.exch", ignoreDeclarationExceptions = "true"),
        key = "orderRoutingKey")
  )
  public void processOrder(Order order) {
    ...
  }

  @RabbitListener(bindings = @QueueBinding(
        value = @Queue,
        exchange = @Exchange(value = "auto.exch"),
        key = "invoiceRoutingKey")
  )
  public void processInvoice(Invoice invoice) {
    ...
  }

  @RabbitListener(queuesToDeclare = @Queue(name = "${my.queue}", durable = "true"))
  public String handleWithSimpleDeclare(String data) {
      ...
  }

}

在第一個示例中,佇列 `myQueue` 會被自動宣告(持久化),如果需要,還會連同交換器一起宣告,並使用路由鍵繫結到該交換器。在第二個示例中,宣告並綁定了一個匿名(排他,自動刪除)佇列;佇列名稱由框架使用 `Base64UrlNamingStrategy` 建立。不能使用此技術宣告 Broker 命名佇列;它們需要宣告為 bean 定義;請參閱容器和 Broker 命名佇列。可以提供多個 `QueueBinding` 條目,讓監聽器監聽多個佇列。在第三個示例中,如果需要,聲明瞭一個名稱取自屬性 `my.queue` 的佇列,並使用佇列名稱作為路由鍵繫結到預設交換器。

自 2.0 版本起,`@Exchange` 註解支援包括自定義型別在內的任何交換器型別。更多資訊請參閱AMQP 概念

當需要更高階的配置時,可以使用普通的 `@Bean` 定義。

請注意第一個示例中交換器上的 `ignoreDeclarationExceptions`。這允許,例如,繫結到一個可能具有不同設定(例如 `internal`)的現有交換器。預設情況下,現有交換器的屬性必須匹配。

從 2.0 版本開始,現在可以將佇列繫結到具有多個路由鍵的交換器,如下例所示

...
    key = { "red", "yellow" }
...

還可以在 `@QueueBinding` 註解中為佇列、交換器和繫結指定引數,如下例所示

@RabbitListener(bindings = @QueueBinding(
        value = @Queue(value = "auto.headers", autoDelete = "true",
                        arguments = @Argument(name = "x-message-ttl", value = "10000",
                                                type = "java.lang.Integer")),
        exchange = @Exchange(value = "auto.headers", type = ExchangeTypes.HEADERS, autoDelete = "true"),
        arguments = {
                @Argument(name = "x-match", value = "all"),
                @Argument(name = "thing1", value = "somevalue"),
                @Argument(name = "thing2")
        })
)
public String handleWithHeadersExchange(String foo) {
    ...
}

請注意,佇列的 `x-message-ttl` 引數設定為 10 秒。由於引數型別不是 `String`,我們必須指定其型別——在此例中為 `Integer`。與所有此類宣告一樣,如果佇列已經存在,則引數必須與佇列上的引數匹配。對於 header 交換器,我們將繫結引數設定為匹配具有頭 `thing1` 且值為 `somevalue` 的訊息,並且必須存在頭 `thing2` 且具有任何值。`x-match` 引數表示兩個條件都必須滿足。

引數的名稱、值和型別可以是屬性佔位符 (`${…​}`) 或 SpEL 表示式 (`#{…​}`). `name` 必須解析為 `String`。`type` 的表示式必須解析為 `Class` 或類的完全限定名。`value` 必須解析為可以由 `DefaultConversionService` 轉換為指定型別的值(例如前面示例中的 `x-message-ttl`)。

如果名稱解析為 `null` 或空 `String`,則該 `@Argument` 將被忽略。