更上一層樓
VMware 提供培訓和認證,以加速您的進程。
瞭解更多Spring Integration 上週發布了 1.0 GA,因此,受到 SpringONE Americas 中 Adrian 的主題演講(不,不是 Monty Python 的小品,只是 Grails 的 live-coding 範例)的啟發,我認為展示如何在 Grails 應用程式這種稍微不同的環境中利用 Spring Integration 會很有趣。
請注意:這是從我自己的部落格 @ www.russmiles.com 轉載的文章。
這一系列文章將探討如何在多種配置中將 Spring Integration 新增到 Grails,最終形成一個完整的 Grails Spring Integration 外掛程式。更像是一個線上日記,您將有機會看到我們如何採取第一步,將 Spring Integration 導入 Grails 應用程式,通過使用 Spring Integration 的一些更進階功能來橋接跨不同基礎架構的消息,最後應用此經驗來建立一個 Grails 外掛程式,以便您可以快速輕鬆地將 Spring Integration 新增到您自己的 Grails 專案中。
如果您希望在閱讀本文時擁有完成的專案,則完整的 Grails 專案原始碼可在此處下載(注意:針對 Grails 1.1 Beta 1 建構)
要建立您的 Grails 應用程式,您所要做的就是確保您的 Grails 安裝位於您的路徑上,然後從命令列發出以下命令
> grails create-app grails-plus-integration-demo
如果一切正常,您應該會看到以下輸出
... 首先是一些其他輸出,然後 ...
已在 <您的目錄>/grails-plus-integration-demo 建立 Grails 應用程式
Grails 現在從您輸入 grails create-app 命令的任何位置,在 grails-plus-integration-demo 目錄中建立了一個應用程式。 將目錄變更為您的新 Grails 應用程式,然後執行它以確保一切正常
> cd grails-plus-integration-demo > grails run-app
您應該會看到類似以下的輸出
... 其他輸出然後 ...
伺服器正在執行。 瀏覽至 https://127.0.0.1:8080/grails-plus-integration-demo
開啟您選擇的瀏覽器並導覽至您正在執行的 grails 應用程式的位址,該位址應為 https://127.0.0.1:8080/grails-plus-integration-demo,您應該會看到類似以下內容
圖 1. 您新的 Grails 應用程式,已啟動並執行
好的,到目前為止沒有什麼突破性的,但現在我們都已準備好建立一些最終將執行 Spring Integration 消息傳遞管道的功能。 若要從命令列關閉您的 Grails 應用程式,請按 Ctrl-C。
對於本文中我們非常簡單的範例應用程式,我們只需要一個名為 "GreetingsMessage" 的網域物件。 若要執行此操作,請從您的新應用程式的目錄中使用以下 grails 命令
> grails create-domain-class GreetingsMessage
然後您應該會看到類似以下內容
正在執行指令碼 /Applications/SpringSource/grails/grails-1.1-beta1/scripts/CreateDomainClass.groovy 環境設定為開發 針對 GreetingsMessage 建立 DomainClass 針對 GreetingsMessage 建立測試
建立 GreetingsMessage 網域類別後,就可以新增一些屬性了。 若要執行此操作,您需要編輯 GreetingsMessage.groovy 檔案,該檔案目前位於您的 grails-app/domain 目錄中。 您只需要新增一行,我們的範例即可讓我們傳送一個字串消息,作為 GreetingsMessage 物件的內容
圖 2. 使用一個屬性更新您的網域類別
儲存您更新的 GreetingsMessage 網域類別,就完成了。
使用命令列,建立一個名為 "GreetingsMessageSender" 的 grails 控制器
> grails create-controller GreetingsMessageSender
此命令應發出類似以下內容
正在執行指令碼 /Applications/SpringSource/grails/grails-1.1-beta1/scripts/CreateController.groovy 環境設定為開發 針對 GreetingsMessageSender 建立 Controller [mkdir] 已建立目錄: /Users/russellmiles/project/grails-plus-integration-demo/grails-app/views/greetingsMessageSender 針對 GreetingsMessageSender 建立測試
您現在已經為其功能建立了一個空的控制器和一些單元測試。 Grails 還在您的 grail-app/views 目錄中建立了一個空目錄,名為 greetingsMessageSender,當您新增一些控制器方法時,它將包含您的檢視範本。
下一步是使用我們希望它支援的方法更新控制器。 開啟並更新 grails-app/controllers/GreetingsMessageSender.groovy,使其符合以下內容
圖 3. (部分) 完成的 GreetingsMessageSender 控制器
如果您不太熟悉 Groovy,那麼以下是類別程式碼所做的
此 send.gsp 檢視中有很多程式碼,因此我建議您在此處下載程式碼,而不是自己輸入所有程式碼。 但是,如果您覺得勇敢,則可以將以下顯示的程式碼複製到您的 send.gsp 檔案中
圖 4. 完成的 send.gsp 檢視
檢視中要關注的關鍵程式碼片段是 g:form 和 flash.message 區段。 g:form 包含一個單一的輸入文字方塊,它將表單中的 content 欄位填入 HTTP 參數中,然後當提交表單時,GreetingsMessageSenderController 上的 send 閉包會拾取這些參數。
flash.message 程式碼顯示快閃集合的內容,在本例中是由 send 閉包新增的消息。
您現在已準備好執行並嘗試此簡單介面,儘管我們預計它暫時不會做太多事情。 使用 grails run-app 命令再次執行您的應用程式,然後導覽至您應用程式的首頁,以嘗試它
圖 5. 您的 Grails 應用程式首頁上的新控制器連結
按一下 GreetingsMessageController 會導致執行 'index' 方法,這會導致您的瀏覽器重新導向到 send 閉包,然後您應該會看到您的新表單
圖 6. 您的傳送表單
您應該能夠在文字方塊中輸入消息,按一下 "Send",然後,好吧,什麼也不會發生... 尚未。
計畫是建立一個服務,該服務接受一個字串,然後簡單地將其推送到大寫字母。 這裡沒有什麼太令人興奮的事情,但這才是最精彩的部分:我們將使其前端控制器不知道控制器在哪裡或它支援什麼介面。 當然,我們可以簡單地將我們的服務注入到控制器中,但這會在介面層級將我們的控制器與服務聯繫起來。 我們在這裡要做的是將服務和控制器之間的合約體現為僅僅是將傳遞的消息類型,在本例中是包含單一字串的消息。
注意:當我提到合約和訊息傳遞時,SOA 的朋友們可能會豎起耳朵。他們會發現這與服務的目的非常接近,服務會將合約聲明為與服務端點交換的訊息類型。這絕對是有意為之,但值得一提的是,雖然 Spring Integration 是 SOA 實踐的一個很好的促進者,但它遠沒有像擁有一個分散式、單體式的 ESB 那麼重量級,即使它共享一些相同的架構基礎(如訊息傳遞和端點)。典型的 ESB 實現往往會導致昂貴的 Web 服務調用,以實現最瑣碎的交換,並帶有各種各樣的包袱,而 Spring Integration 允許完全控制,可以將交換從線程內訊息傳遞、通過多線程進程內輪詢,一直擴展到進程間/機器間交換(如果需要的話)(更多內容將在本系列的後續文章中介紹)。
第一步是將 Spring Integration 函式庫添加到我們的範例應用程式中。Grails 為應用程式直接依賴的函式庫提供了一個特定的、每個應用程式的位置。最簡單的方法是將 Spring Integration 發布目錄 (dist directory) 的內容複製到我們的 Grails 應用程式的 lib 目錄。
複製 Spring Integration 發布目錄 (dist directory) 的內容...
...到 Grails 應用程式根目錄中的 lib 目錄。
新增函式庫使 Spring Integration 可用於您的 Grails 應用程式。現在您已準備好創建您的 Spring Integration 管道,在創建將服務該管道的元件之後。
> grails create-service DemoBean
執行此命令應會產生類似於以下的輸出
Running script /Applications/SpringSource/grails/grails-1.1-beta1/scripts/CreateService.groovy Environment set to development Created Service for DemoBean Created Tests for DemoBean
現在 Grails 已經在 grails-app/services 目錄中創建了一個 DemoBeanService。它不是最有趣的服務,但它將有助於說明 Spring Integration 機制。
要完成服務,請在 grails-app/services 目錄中打開 DemoBeanService.groovy 檔案,並將其完成如下所示
圖 7. 您已完成的 DemoBeanService 類別
該服務有一個方法,其目的是將任何傳入的字串轉換為大寫,然後返回。現在您有了一個服務,您希望在使用者將字串提交到控制器時調用它,現在是將這兩者連接在一起的時候了。
現在,我們可以直接使用 DI,但在此範例中,我們將透過使用 Spring Integration 來處理將傳入的字串傳遞到我們配置的特定服務,以此奠定更靈活的架構基礎。
Grails 支援使用一個約定將現有的 Spring XML 配置新增到應用程式中,該約定將配置保存在 grails-app/conf/spring 目錄中的 resources.xml 檔案中。為了節省您一些打字時間,在此處下載該檔案,然後將其放入您的 grails-app/conf/spring 目錄中。
接下來,在您最喜歡的文字編輯器中打開 resources.xml,讓我們看看發生了什麼。
首先,請注意我們正在引入 Spring Integration 命名空間,以便我們可以使用與 Spring Integration 基於 XML 的領域特定語言相關聯的元素和屬性。實際上,Spring Integration 命名空間被設定為文檔的預設命名空間,因此我們必須使用命名空間來限定 bean 元素。
然後,整個管道都表示在此文檔中。主要元件以及這些元件在此管道中滿足的角色如下
注意:Grails 中的所有服務類別預設都會產生該類別的單例服務物件,該物件在 Spring 應用程式上下文中以類別名稱的 camel-cased 版本建立索引。因此,當 service-activator 引用 demoBeanService bean 時,Grails 會自動將其解析為我們先前創建的 DemoBeanService 的單例實例。
就是這樣,我們有一個完整的訊息傳遞管道,它將通過一個內部佇列傳遞訊息,從而將任何訊息提供者與消費者強烈解耦。您會注意到,任何創建訊息並調用閘道的消費者都不需要知道訊息最終會在哪裡,甚至不需要知道該目標端點實現了什麼介面。此處的合約是要傳遞的訊息類型,對於這個簡單的範例來說,僅僅是字串。
要將鬆散的兩端連接起來,您需要創建一個您樂意暴露給控制器的服務介面。請注意,端點引用的實際 bean 不一定需要實現相同的介面,重要的是訊息參數。
要創建介面,請在 src/java 目錄中創建一個名為 MessageService.java 的 Java 介面,並位於適當的包結構(如 com.russmiles.demo.grails.integration)中。完成介面,使其與以下內容匹配
圖 8. MessageService 介面的定義
現在您已經定義了閘道介面,最後的工作是將閘道本身連結到您的控制器中。在 Grails 中,您可以根據物件的名稱自動為物件提供依賴項,因此要從控制器內部訪問閘道,您需要做的就是聲明一個名稱與閘道的 id 匹配的屬性
圖 9. 將閘道的依賴項新增到您的控制器中
現在您已經將閘道連結到控制器中,您可以修改您的 send 閉包以使用它
圖 10. 您已完成的控制器
就是這樣,是時候啟動您的使用 Spring Integration 的 Grails 應用程式了。
一切都連接在一起後,剩下的就是運行您的應用程式。使用通常的命令運行 Grails 應用程式
> grails run-app
現在訪問您瀏覽器中的 GreetingsMessageSenderController,如下所示
圖 11. 您的表單已準備好輸入以觸發您的 Spring Integration 管道
在表單中輸入一些文字,然後點擊“Send”
圖 12. 一些資料輸入到表單中,準備就緒
以下圖表顯示了接下來應該發生的事情
圖 13. 您的訊息已通過管道發送並返回處理,以作為 flash 訊息的一部分顯示
重申一下,這是您點擊“Send”按鈕時發生的情況。
當您點擊發送時,您的控制器將調用閘道,閘道會將訊息作為 Spring Integration 訊息傳遞到適當的通道,然後服務啟動器將獲取該訊息,解壓縮它並調用 demoBean 服務。該服務獲取字串內容並將其轉換為大寫,然後通過為此交換設定的臨時通道返回結果。閘道上的方法返回,取消阻塞控制器,然後控制器使用 flash 集合中的結果來呈現視圖。