脈絡:應用程式之間透過 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 Consumer 或 Event-Driven Consumer
- 多個消費者可以用 Competing Consumers 或透過 Message Dispatcher 從同一通道接收訊息
- 可用 Selective Consumer 決定要消費或忽略哪些訊息
- 可用 Durable Subscriber 確保訂閱者不會錯過在端點離線期間發布的訊息
- 消費者也可以是 Idempotent Receiver,正確地偵測並處理重複訊息