EIP '貸款經紀人' 參考實作 (第一部分)

工程 | Oleg Zhurakousky | 2010年3月19日 | ...

我們很高興宣布推出「貸款經紀人」參考實作的第一部分。「貸款經紀人」概念已成為展示 企業整合模式 (EIP) 的事實參考領域 - 作者為 Gregor Hohpe 和 Bobby Woolf,而此貸款經紀人 RI 的第一部分示範了如何使用 Spring Integration (SI) 框架實現和應用企業整合模式

簡介

lb-pipesFilters

EIP 架構的核心是非常簡單但功能強大的概念:管道與篩選器訊息。端點(篩選器)透過通道(管道)相互連接。生產端點將訊息傳送到通道,而訊息由消費端點檢索。  此架構旨在定義各種機制,描述端點之間如何交換資訊的方式,而無需了解這些端點是什麼或它們正在交換什麼資訊,從而提供非常鬆散耦合且靈活的協作模型,同時也將整合考量業務考量分離。EIP 透過進一步定義來擴展此架構

  • 管道的類型(點對點通道、發布-訂閱通道、通道轉接器等)
  • 核心篩選器和圍繞篩選器如何與管道協作的模式(訊息路由器、分割器和聚合器、各種訊息轉換模式等)
Spring Integration (SI) 訊息傳遞框架旨在提供基於 POJO 的程式設計模型,該模型建立在企業整合模式之上。

使用案例

此使用案例的詳細資訊和變化在 EIP 書籍第 9 章 中有非常好的描述,但以下是簡要摘要:消費者在尋找最佳貸款報價時,會訂閱貸款經紀人的服務,貸款經紀人處理諸如
  1. 消費者預先篩選(例如,取得並審查消費者的信用記錄)
  2. 確定最合適的銀行(例如,根據消費者的信用記錄/評分)
  3. 向每家選定的銀行發送貸款報價請求
  4. 收集每家銀行的回覆
  5. 根據消費者的需求,篩選回覆並確定最佳報價。
  6. 將貸款報價傳回給消費者。
顯然,獲得貸款報價的實際過程要複雜得多,但由於我們在這裡的目標是展示如何在 SI 中實現和實施企業整合模式,因此使用案例已簡化為僅關注流程的整合方面。這並不是試圖為您提供消費者財務方面的建議。loan-broker-1 如您所見,透過聘請貸款經紀人,消費者與貸款經紀人營運的細節隔離開來,而每家貸款經紀人的營運方式可能彼此不同,以保持競爭優勢,因此我們組裝/實施的任何東西都必須具有彈性,以便可以快速且輕鬆地引入任何變更。說到變更,貸款經紀人 RI 的第一部分實際上並未與任何「虛擬」銀行或徵信機構交談。這些服務都被 Stub 掉了。我們在這裡的目標是組裝、協調和測試整個流程的整合方面。只有這樣,我們才能開始考慮將此流程連接到實際服務。我們將在第 2 部分中執行此操作,您將在那裡意識到分離整合業務考量的真正好處。您將看到,描述此流程的流程和配置不會改變,無論特定貸款經紀人處理的銀行數量,還是用於與這些銀行通信的通信媒介(或協定)類型(JMS、WS、TCP 等)。

設計

當您分析上述 6 個需求時,您會很快發現它們都屬於整合考量的範疇。例如,在消費者預先篩選步驟中,我們需要收集有關消費者和消費者需求的額外資訊,並使用額外的元資訊豐富貸款請求。然後,我們必須篩選此類資訊以選擇最合適的銀行列表,依此類推。豐富、篩選、選擇 - 這些都是 整合考量,EIP 為此定義了模式形式的解決方案。SI 提供了這些模式的實作。

提交貸款報價請求 - 訊息閘道

lb-gateway

訊息閘道模式提供了一種簡單的機制來存取訊息傳遞系統,包括我們的貸款經紀人。在 SI 中,您將閘道定義為 Plain Old Java Interface(無需提供實作),透過 XML <gateway> 元素或透過註解進行配置,並像任何其他 Spring bean 一樣使用它。SI 將透過產生訊息(有效負載映射到方法的輸入參數)並將其發送到指定的通道,來處理委派和將方法調用映射到訊息傳遞基礎設施。

LoanBrokerGateway.java 是代表消費者使用的訊息閘道的介面

閘道 XML 配置

<int:gateway id="loanBrokerGateway"
		     default-request-channel="loanBrokerPreProcessingChannel"
		     service-interface="org.springframework.integration.loanbroker.LoanBrokerGateway"/>

在上述配置中,每當在 'loanBrokerGateway' bean 上調用任何方法時,都會建構一個訊息並將其發送到 'loanBrokerPreProcessingChannel'。

我們對訊息閘道的定義 (LoanBrokerGateway.java) 為消費者提供了兩種與貸款經紀人互動的方式。消費者可以透過調用 getLoanQuote(loanRequest) 方法請求單一(最佳)報價,或透過調用 getAllLoanQuotes(loanRequest) 方法請求所有報價。這表示我們的貸款經紀人必須知道貸款請求的類型。我們也知道有一些預先篩選步驟,例如取得和評估消費者的信用評分,因為某些頂級銀行通常只接受信用評分符合最低要求的消費者的報價請求。

基本上,整個過程類似於看醫生,在看到真正的醫生之前,您會先見到護士,護士會測量您的體溫、血壓等,並記錄醫生需要的「元資訊」列表。
在 EIP 中,訊息是一個簡單的結構,由訊息有效負載訊息標頭組成。訊息標頭是儲存與訊息相關的元資訊的絕佳機制。那麼,我們如何使用額外資訊豐富我們的訊息呢?EIP 定義了 內容豐富器 模式,該模式描述了如何使用額外資訊擴充訊息。Spring Integration 提供了 <header-enricher> 元素,讓您可以快速豐富傳輸中的訊息。但是,由於我們的貸款經紀人必須在發送報價之前執行多項任務,因此如果還有一種機制可以從一組獨立的任務中組合流程,那就太好了。

貸款請求預先篩選 – 組合訊息處理器內容豐富器

組合訊息處理器模式描述了圍繞建立端點的規則,這些端點保持對訊息流的控制,訊息流由多個訊息處理器組成。在我們的案例中,預先篩選流程包含 3 個步驟:a) 確定貸款請求的類型; b) 取得消費者的信用記錄和評分; c) 確定(基於某些標準)通道列表(每個通道對應一家銀行)

Spring Integration 允許您透過 <chain> 元素組合複雜的處理器

<int:chain id="preScreening" input-channel="loanBrokerPreProcessingChannel" output-channel="banksDistributionChannel">
	<int:header-enricher>
		<int:header name="RESPONSE_TYPE"
			expression="headers.history.iterator().next().attributes['method'].equals('getLoanQuote') ? 'BEST' : 'ALL'" />
	</int:header-enricher>
	<int:header-enricher>
		<int:header name="CREDIT_SCORE" ref="creditBureau" method="getCreditScore"/>
	</int:header-enricher>
	<int:header-enricher>
		<int:header name="BANKS" ref="bankSelector" method="selectBankChannels"/>
	</int:header-enricher>
</int:chain>
lb-chain

這將建立一個 bean 'preScreening' 作為 SI 端點,它也定義了一個 輸入/輸出-通道 來接收和發送訊息。上面的由 3 個 header-enricher 處理器組成。第一個將透過利用 SpEL 同時存取 訊息歷史記錄 並根據調用的閘道方法確定此標頭的值來設定 RESPONSE_TYPE 標頭。

此範例說明了如何在確定標頭值時使用 SpEL 執行簡單的評估,但我們不提倡使用 SpEL 執行複雜的業務邏輯
接下來,我們有一個 header-enricher,它映射到一個負責從徵信局取得信用評分的流程(目前為 Stub CreditBureauStub)並設定 CREDIT_SCORE 標頭。最後一個 header-enricher 使用 BankChannelSelector(請參閱 bankSelector 配置)。BankChannelSelector.selectBankChannels(..) 方法的實作將訊息作為輸入,並傳回一個 Set<String> 值,其中包含通道的名稱,這些通道將設定為 BANKS 標頭。這完成了我們的預先篩選流程,我們的貸款經紀人現在準備好透過 banksDistributionChannel 向每家選定的銀行發送貸款請求。

BANKS 標頭定義了動態產生和篩選的通道列表,每個通道都充當代表銀行的接收者。我們需要一個端點,允許我們將相同的訊息發送到所有接收者。

將貸款報價請求分發到選定的銀行 - 收件者列表

lb-recipientList EIP 定義了各種路由模式,這些模式都源自 訊息路由器。其中之一是 收件者列表 路由器,它將訊息路由到列表中的所有收件者。SI 提供了 <router> 元素,允許我們配置路由器,在我們的案例中,路由器將從 bankDistributionChannel 接收訊息。此路由器將透過 SpEL 表達式從 BANKS 訊息標頭 取得銀行通道列表(此列表在預先篩選步驟中設定),並將訊息分發到這些通道

下面的 XML 配置顯示了如何配置此路由器

<int:router id="bankRecipientListRouter" input-channel="banksDistributionChannel" 
								expression="headers['BANKS']" 
								apply-sequence="true"/>
您可以清楚地看到我們如何透過透過通道(管道)連接各種端點(篩選器)來組裝貸款經紀人,同時傳遞訊息。您也可以看到我們正在透過基於 POJO 的程式設計技術來完成它,幾乎沒有使用 Spring Integration API(只有 BankChannelSelector.java)。SI 負責將我們的 POJO 與訊息傳遞基礎設施介接。
貸款經紀人需要做的最後一件事是接收來自銀行的貸款報價,按消費者聚合它們(我們不想向另一個消費者顯示來自一個消費者的報價),根據消費者的選擇標準(單一最佳報價或所有報價)組裝回覆,然後回覆消費者。

聚合貸款報價回覆 - 聚合器

聚合器模式描述了一個端點,該端點將相關的訊息分組為單個訊息。可以提供標準和規則來確定聚合關聯策略。SI 提供了聚合器模式的幾種實作以及基於方便命名空間的配置。

lb-complete

我們的貸款經紀人透過 <aggregator> 元素定義了一個 'loanQuoteAggregator' bean,它提供了預設的聚合器關聯策略。預設關聯策略根據 $corelationId 標頭關聯訊息(請參閱 關聯識別碼 模式)。有趣的是,我們從未提供此標頭的值。  它是由收件者列表路由器在稍早自動設定的,當時它為每家銀行產生了一個單獨的訊息。

訊息關聯後,它們會發佈到實際的聚合器實作。雖然 SI 提供了預設聚合器,但其策略(從所有訊息收集有效負載列表並使用此列表作為有效負載建構新訊息)不符合我們的要求。原因是我們的消費者可能需要單一最佳報價或所有報價。為了傳達消費者的請求,我們在流程的早期設定了 RESPONSE_TYPE 標頭。現在我們必須評估此標頭並傳回所有報價(預設聚合策略會起作用)或最佳報價(預設聚合策略將不起作用,因為我們必須確定哪個貸款報價是最佳的)。

<int:aggregator id="loanQuoteAggregator" input-channel="quotesAggregationChannel" method="aggregateQuotes">
	<bean class="org.springframework.integration.loanbroker.LoanQuoteAggregator"/>
</int:aggregator>

顯然,選擇最佳報價可能基於複雜的標準,並且會影響聚合器的複雜性,但目前我們使其變得簡單。如果消費者想要最佳報價,我們將選擇利率最低的報價。為了實現這一點,LoanQuoteAggregator.java 將對所有報價進行排序並傳回第一個。 LoanQuote.java 實作了 Comparable,它根據 rate 屬性比較報價。

建立回覆訊息後,它會被發送到啟動流程的訊息閘道的 default-reply-channel(因此是消費者)。我們的消費者收到了貸款報價!

需要注意的一個重要事項是,我們沒有在 <gateway> 元素上定義 default-reply-channel 屬性。事實上,我們沒有明確定義單個通道。與其他訊息傳遞系統類似,SI 將根據需要自動建立輸入和預設回覆通道,為您提供另一種進一步簡化 Spring 應用程式內容配置的方法。

結論

「貸款經紀人」使用案例的此參考實作是使用 Spring Integration 框架完成的;這是一個基於 POJO、輕量級、可嵌入的訊息傳遞框架,具有鬆散耦合的程式設計模型,旨在簡化異質系統的整合,而無需使用重型 ESB 類型的引擎或專有開發和部署環境。它建立在企業整合模式之上。「模式旨在描述您解決方案的「建構區塊」- 它們本身並非旨在成為解決方案。因此,模式最適合由輕量級、可嵌入的框架來實作,這些框架用於支援您的解決方案,而不是旨在控制它的重型商業現成產品。這就是大型供應商在 SOA 方面都犯錯的地方...」- Tom McCuch (SpringSource) 在 Joshua Long 的 InfoQ 文章中評論道。整合考量存在於所有類型的應用程式(基於伺服器和非基於伺服器)中,如果這些應用程式需要相互整合,則不應要求變更設計、測試和部署策略。我(開發人員)不應該僅僅因為我有整合考量而將我的 SWT 或基於控制台的應用程式移植到類似 ESB 的伺服器或實作專有介面。我只是希望有一個框架可以讓我隨時解決這些考量,並且對我的程式碼或基礎設施進行最少的變更或不進行任何變更。Spring Integration 就是那個框架。

在下一部分中,我們將透過使用這些轉接器替換我們的 Stub 服務來示範 Spring Integration 中可用的各種遠端轉接器和技術,並將介紹與「貸款經紀人」使用案例相關的非同步整合樣式。

資源:

「貸款經紀人」參考實作隨 Spring Integration 2.0.M3 的發布而提供(請參閱「下載」部分)。它作為獨立的 Eclipse/Maven 專案分發。您也可以從我們的 Subversion 儲存庫中將其檢出為專案。

$> svn co https://src.springframework.org/svn/spring-integration/trunk/spring-integration-samples/loan-broker/ loan-broker $> cd loan-broker $> mvn install

相關連結Spring Integration Spring Integration in Action 企業整合模式 Spring Integration 入門指南 (Joshua Long) 敏捷 SOA - 第 1、2 和 3 部分 (Tom McCuch)

感謝 Gary Russel (Spring Source,SI 提交者) 和 Dave Turanski (Spring Source) 協助撰寫此部落格!

取得 Spring 電子報

與 Spring 電子報保持聯繫

訂閱

領先一步

VMware 提供培訓和認證,以加速您的進度。

了解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

了解更多

即將舉行的活動

查看 Spring 社群中所有即將舉行的活動。

查看全部