脈絡:應用程式之間透過 Message Channel 互送 Message 來溝通。

兩套各自獨立的軟體#

應用程式與訊息系統是兩套各自獨立的軟體:應用程式為某種使用者提供功能,訊息系統則管理用於傳輸訊息的通道。

即使訊息系統被納為應用程式的根本組成,它仍是一個獨立的、專門的功能提供者——就像資料庫管理系統或網頁伺服器那樣。正因為兩者分離,它們必須有辦法連起來並協同工作。

訊息系統是一種伺服器,能接受請求並回應它們——就像資料庫接受與取出資料,訊息伺服器接受與遞送訊息。

伺服器需要客戶端,而使用訊息傳遞的應用程式就是訊息伺服器的客戶端。但應用程式未必知道怎麼當一個訊息客戶端,就像它未必知道怎麼當資料庫客戶端一樣。訊息伺服器和資料庫伺服器一樣有一套客戶端 API 供應用程式與之互動;這套 API 不是應用程式專屬的,而是領域專屬的——這裡的領域就是訊息傳遞。

因此,應用程式必須包含一段程式碼,把訊息領域與應用程式接合起來,讓應用程式得以進行訊息傳遞。

解法#

Message Endpoint 的程式碼同時客製於應用程式與訊息系統的客戶端 API。應用程式的其餘部分幾乎不需要知道訊息格式、訊息通道,或任何透過訊息與其他應用程式溝通的細節——它只知道自己有一個請求或一份資料要送給別的應用程式,或正期待從別的應用程式收到這些東西。

把命令或資料做成訊息、送上特定通道的,是端點程式碼;接收訊息、取出內容、以有意義的方式交給應用程式的,也是端點。

封裝帶來的好處#

Message Endpoint 把訊息系統對應用程式的其餘部分封裝起來,並把通用的訊息 API 客製成特定應用程式與任務所需的樣子

  • 若應用程式從一套訊息 API 換到另一套,開發者只需重寫端點程式碼,其餘部分維持不變
  • 若訊息系統新版本改了 API,理應只影響端點程式碼
  • 若應用程式決定改用訊息傳遞以外的方式溝通,理想上開發者只需把端點程式碼換掉,應用程式其餘部分仍然不動

使用上的性質#

  • 一個 Message Endpoint 可以用來送訊息或收訊息,但單一實例不會兩者都做
  • 端點是通道專屬的,因此單一應用程式會用多個端點來介接多個通道。
  • 應用程式也可能對同一個通道使用多個端點,通常是為了支援多條並行執行緒。

Message Endpoint 是一種特化的 Channel Adapter——一種為其應用程式量身開發並整合進去的轉接器。

接下來#

Message Endpoint 應該設計成 Messaging Gateway,把訊息程式碼封裝起來、對應用程式其餘部分隱藏訊息系統。此外:

  • 可用 Messaging Mapper 在領域物件與訊息之間搬運資料
  • 可組織成 Service Activator,替同步的服務或函式呼叫提供非同步的訊息存取
  • 端點可以作為 Transactional Client,明確地控制與訊息系統之間的交易
  • 接收端可以是 Polling ConsumerEvent-Driven Consumer
  • 多個消費者可以用 Competing Consumers 或透過 Message Dispatcher 從同一通道接收訊息
  • 可用 Selective Consumer 決定要消費或忽略哪些訊息
  • 可用 Durable Subscriber 確保訂閱者不會錯過在端點離線期間發布的訊息
  • 消費者也可以是 Idempotent Receiver,正確地偵測並處理重複訊息
範例:JMS 與 .NET 中的端點型別

JMS Producer 與 Consumer#

在 JMS 中,兩個主要的端點型別是送訊息用的 MessageProducer 與收訊息用的 MessageConsumer。Message Endpoint 使用其中之一的實例,對特定通道收送訊息。

.NET MessageQueue#

在 .NET 中,主要的端點類別與主要的 Message Channel 類別是同一個MessageQueue。Message Endpoint 使用 MessageQueue 的實例,對特定通道收送訊息。