AMQP 抽象概念

Spring AMQP 由兩個模組組成(每個模組在發行版中以 JAR 表示):spring-amqpspring-rabbit。「spring-amqp」模組包含 org.springframework.amqp.core 套件。在該套件中,您可以找到代表核心 AMQP「模型」的類別。我們的目的是提供通用的抽象概念,這些概念不依賴於任何特定的 AMQP Broker 實作或用戶端程式庫。終端使用者程式碼可以更方便地跨供應商實作移植,因為它可以僅針對抽象層進行開發。這些抽象概念然後由 Broker 特定的模組實作,例如「spring-rabbit」。目前只有 RabbitMQ 實作。但是,除了 RabbitMQ 之外,這些抽象概念已在使用 Apache Qpid 的 .NET 中驗證。由於 AMQP 在協定層級運作,原則上,您可以將 RabbitMQ 用戶端與任何支援相同協定版本的 Broker 一起使用,但目前我們未測試任何其他 Broker。

此概述假設您已熟悉 AMQP 規範的基本知識。如果沒有,請查看其他資源中列出的資源

Message

0-9-1 AMQP 規範未定義 Message 類別或介面。相反地,在執行諸如 basicPublish() 之類的操作時,內容會作為位元組陣列引數傳遞,而其他屬性會作為個別引數傳遞。Spring AMQP 定義了 Message 類別,作為更通用的 AMQP 網域模型表示的一部分。Message 類別的目的是將主體和屬性封裝在單一實例中,以便 API 可以反過來更簡潔。以下範例顯示了 Message 類別定義

public class Message {

    private final MessageProperties messageProperties;

    private final byte[] body;

    public Message(byte[] body, MessageProperties messageProperties) {
        this.body = body;
        this.messageProperties = messageProperties;
    }

    public byte[] getBody() {
        return this.body;
    }

    public MessageProperties getMessageProperties() {
        return this.messageProperties;
    }
}

MessageProperties 介面定義了幾個常見的屬性,例如 'messageId'、'timestamp'、'contentType' 以及更多。您也可以透過呼叫 setHeader(String key, Object value) 方法,使用使用者定義的「標頭」來擴充這些屬性。

從版本 1.5.71.6.111.7.42.0.0 開始,如果訊息主體是序列化的 Serializable Java 物件,則在執行 toString() 操作(例如在記錄訊息中)時,預設不再還原序列化。這是為了防止不安全的還原序列化。預設情況下,僅還原序列化 java.utiljava.lang 類別。若要恢復先前的行為,您可以透過調用 Message.addAllowedListPatterns(…​) 來新增允許的類別/套件模式。支援簡單的 ** 通配符,例如 com.something.***.MyClass。無法還原序列化的主體在記錄訊息中以 byte[<size>] 表示。

Exchange (交換器)

Exchange 介面代表 AMQP 交換器,訊息生產者將訊息傳送到該交換器。Broker 的虛擬主機中的每個交換器都有一個唯一的名稱以及一些其他屬性。以下範例顯示了 Exchange 介面

public interface Exchange {

    String getName();

    String getExchangeType();

    boolean isDurable();

    boolean isAutoDelete();

    Map<String, Object> getArguments();

}

如您所見,Exchange 也具有由 ExchangeTypes 中定義的常數表示的「類型」。基本類型為:directtopicfanoutheaders。在核心套件中,您可以找到每個類型的 Exchange 介面的實作。這些 Exchange 類型在處理與佇列的綁定方面,行為各不相同。例如,Direct 交換器允許佇列透過固定的路由金鑰(通常是佇列的名稱)綁定。Topic 交換器支援使用路由模式的綁定,路由模式可能包含用於「正好一個」的 '*' 和用於「零個或多個」的 '#' 通配符。Fanout 交換器會發佈到綁定到它的所有佇列,而無需考慮任何路由金鑰。有關這些和其他交換器類型的更多資訊,請參閱其他資源

AMQP 規範還要求任何 Broker 提供一個沒有名稱的「預設」直接交換器。宣告的所有佇列都以其名稱作為路由金鑰綁定到該預設 Exchange。您可以在AmqpTemplate中了解有關 Spring AMQP 中預設交換器用法的更多資訊。

Queue (佇列)

Queue 類別代表訊息消費者從中接收訊息的元件。與各種 Exchange 類別一樣,我們的實作旨在作為此核心 AMQP 類型的抽象表示。以下清單顯示了 Queue 類別

public class Queue  {

    private final String name;

    private volatile boolean durable;

    private volatile boolean exclusive;

    private volatile boolean autoDelete;

    private volatile Map<String, Object> arguments;

    /**
     * The queue is durable, non-exclusive and non auto-delete.
     *
     * @param name the name of the queue.
     */
    public Queue(String name) {
        this(name, true, false, false);
    }

    // Getters and Setters omitted for brevity

}

請注意,建構子採用佇列名稱。根據實作,管理範本可能會提供用於產生唯一命名佇列的方法。此類佇列可用作「回覆至」位址或在其他臨時情況下。因此,自動產生佇列的 'exclusive' 和 'autoDelete' 屬性都將設定為 'true'。

請參閱設定 Broker中關於佇列的章節,以取得有關使用命名空間支援宣告佇列的資訊,包括佇列引數。

Binding (綁定)

假設生產者傳送到交換器,而消費者從佇列接收訊息,那麼將佇列連接到交換器的綁定對於透過訊息傳遞連接這些生產者和消費者至關重要。在 Spring AMQP 中,我們定義了 Binding 類別來表示這些連線。本節回顧了將佇列綁定到交換器的基本選項。

您可以將佇列綁定到具有固定路由金鑰的 DirectExchange,如下列範例所示

new Binding(someQueue, someDirectExchange, "foo.bar");

您可以將佇列綁定到具有路由模式的 TopicExchange,如下列範例所示

new Binding(someQueue, someTopicExchange, "foo.*");

您可以將佇列綁定到沒有路由金鑰的 FanoutExchange,如下列範例所示

new Binding(someQueue, someFanoutExchange);

我們也提供了 BindingBuilder 以促進「流暢 API」樣式,如下列範例所示

Binding b = BindingBuilder.bind(someQueue).to(someTopicExchange).with("foo.*");
為了清楚起見,前面的範例顯示了 BindingBuilder 類別,但是當對 'bind()' 方法使用靜態匯入時,此樣式效果很好。

就其本身而言,Binding 類別的實例僅保留有關連線的資料。換句話說,它不是「活動」元件。但是,正如您稍後在設定 Broker中將看到的那樣,AmqpAdmin 類別可以使用 Binding 實例來實際觸發 Broker 上的綁定動作。此外,正如您在同一節中看到的那樣,您可以使用 Spring 的 @Bean 註解在 @Configuration 類別中定義 Binding 實例。還有一個方便的基底類別,可以進一步簡化產生 AMQP 相關 Bean 定義的方法,並識別佇列、交換器和綁定,以便在應用程式啟動時在 AMQP Broker 上宣告所有這些。

AmqpTemplate 也定義在核心套件中。作為參與實際 AMQP 訊息傳遞的主要元件之一,它將在其自己的章節中詳細討論(請參閱AmqpTemplate)。