領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多在 SpringSource 的 Groovy & Grails 培訓課程中,我們強調 Grails 是站在巨人的肩膀上。Spring 就是其中一位巨人。沒有 Spring,Grails 根本無法如此快速地發展起來。它很可能也沒有現在這樣輕鬆整合企業 Java 系統的靈活性。看看可用的外掛數量就知道了:許多外掛都基於支援 Spring 的 Java 庫。
在這篇文章中,我想先看看 Grails 如何使用 Spring,然後介紹你可以訪問這種原始力量和靈活性的各種方式。
以下是你在典型的 Grails 應用程式的 Spring 上下文中可能會找到的一些 Bean 的示例
Grails 在其他哪些方面依賴於 Spring?嗯,首先是資料繫結:Spring 負責將字串資料繫結到物件屬性的物理過程。這不僅僅是 Web 層:GORM 使用 Spring 的 Hibernate 模板來儲存和查詢域類。也許最重要的是,Grails 使用 Spring 的事務管理。正如我之前暗示過的,許多外掛都利用了 Java 庫中提供的 Spring 整合。
所以,Grails 應用程式實際上是一個 Spring 應用程式。這就提出了一個問題:當需要時,如何利用底層的 Spring 元件。
有幾種方法可以採用,我將一一介紹。
原則很簡單:在grails-app/services目錄下建立一個類,其後綴為Service,你的應用程式中就會自動獲得一個新的(單例)Spring Bean。這個 Bean 的名稱是什麼?很簡單:類名,首字母小寫。例如,類SecurityService將生成一個名為“securityService”的 Bean。AuditReportService同樣會成為一個“auditReportService” Bean。
將其他 Bean 裝配到你的服務中(以及所有其他核心 Grails 工件)同樣簡單:宣告一個與你想要的 Bean 同名的屬性。例如,假設我想在另一個服務(或可能是控制器)中使用“auditReportService” Bean。我可以像這樣裝配它:
class MyService {
def auditReportService
...
}
我相信你會同意這很簡單的。這是 Spring 自動裝配的一個例子。即使你為屬性指定了型別,Grails 也會按名稱裝配 Bean。
服務是事務性的,這是它們的另一個有用特性。這使它們成為抽象資料訪問和構建健壯應用程式架構的絕佳方式。一種典型的方法是為你的服務建立不同的“閘道器”:HTML UI、XML REST 介面、透過 RMI 進行遠端呼叫等,所有這些都呼叫你的服務。
最後一點:我說 Grails 會將你的服務例項化為單例 Bean,但你可以按服務更改此行為。只需在你的服務類中新增一個靜態scope屬性,如下所示:
class MyService {
static scope = "request"
...
}
如你所見,當你使用服務時,幾乎不費吹灰之力就能獲得 Spring 的許多主要好處。這很棒,但如果你有現有的類想要變成 Bean 怎麼辦?也許你是用 Java 編寫的,或者它們打包在 JAR 檔案中。使用純 Spring,你需要手動配置它們。幸運的是,你也可以在 Grails 中做到這一點。
我必須說,我不再喜歡編寫 XML 了,所以我更喜歡一種替代的 Bean 定義格式:Grails 的 Spring Bean DSL。這是一個定義報表生成器 Bean 的非常簡單的例子,在grails-app/conf/spring/resources.groovy:
beans = {
reportGenerator(org.example.XmlReportGenerator)
}
中。定義以 Bean 名稱(“reportGenerator”)開頭,後跟括號中的類(“XmlReportGenerator”)。你還可以配置 Bean 和 Bean 定義屬性
beans = {
reportGenerator(org.example.XmlReportGenerator) { bean ->
bean.autowire = "byName"
prettyFormat = true
}
}
好的,它比 XML 格式更簡潔,但這足以讓大多數人改用它嗎?可能對大多數人來說還不夠。DSL 的真正威力來自於它是一個真實的 Groovy,這意味著
更新 我已更改下面的示例,以使用檢測當前環境的新方法。
以這個例子為例
import grails.util.Environment
beans = {
if (Environment.current == Environment.PRODUCTION) {
// Use the real web service for production
securityService(org.example.WsClientSecurityService) {
endpoint = "http://..."
}
}
else {
// Use a dummy service for development and testing
securityService(org.example.DummySecurityService) {
userRoles = [ peter: [ "admin", "user"], tom: [ "user" ] ]
}
}
}
它演示瞭如何使用條件為不同的 Grails 環境配置不同的 Bean 實現。對於生產環境,“securityService”是一個 Web 服務客戶端,而對於所有其他環境,我們使用一個虛擬的記憶體服務。你還可以看到,可以將字面量對映賦給一個Map屬性,對於任何其他型別也是如此。它不僅比 XML 更簡潔,而且你還可以使用真實型別和可以在執行時操作的物件。
DSL 的內容比我在這裡介紹的要多,所以我建議你檢視 使用者指南 以獲取更多資訊。你會發現 DSL 支援 Spring 名稱空間、工廠方法等。
我已經涵蓋了 Grails 中最常見的兩個 Spring 整合點,但還有另一個:註解。
package org.example;
@Component("securityService")
public class DummySecurityService implements SecurityService {
...
}
這應該會自動成為一個名為“securityService”的 Spring Bean,但目前還不會發生。還需要一個額外的步驟:你必須指定 Grails 應該掃描哪些包來查詢 Spring 註解。所以在這個例子中,我們希望掃描org.example包。要做到這一點,只需在以下位置新增以下設定:grails-app/conf/Config.groovy:
grails.spring.bean.packages = [ "org.example" ]
現在該類將被自動建立為 Spring Bean。請注意,Grails 也會掃描所有子包,因此即使該類位於org.example.sub.pkg包中,上面的設定也會起作用。
只要透過grails.spring.bean.packages指定了包,你甚至可以使用 @Controller 註解將類新增為控制器。如果你決定從 Spring MVC 遷移到 Grails,或者如果團隊開發了一些你想放入 Grails 應用程式的 Spring MVC 控制器,這會很有幫助。
如你所見,Grails 中定義 Bean 的選項足以滿足大多數人的需求。現在只剩下執行時檢查 Spring 應用程式上下文需要涵蓋了。
如果你的類是 Spring Bean,那麼你可以簡單地實現ApplicationContextAware介面。Spring 將自動將上下文注入到你的applicationContext屬性中。或者,你可以注入grailsApplicationBean 並透過以下方式檢索上下文:grailsApplication.mainContext.
另一方面,如果你的類不受 Spring 管理,你就必須手動處理一些事情。這並不理想,但你可以透過以下程式碼片段獲取上下文:
import org.springframework.web.context.support.WebApplicationContextUtils
import org.codehaus.groovy.grails.web.context.ServletContextHolder
import org.springframework.context.ApplicationContext
...
def ctx = WebApplicationContextUtils.getWebApplicationContext(ServletContextHolder.servletContext)
請注意:你處理的不是 Grails 中的單個應用程式上下文。你從上述不同技術獲得的應用程式上下文有一個父應用程式上下文。該父級包含grailsApplication, pluginManager以及從web-app/WEB-INF/applicationContext.xml檔案配置的其他 Bean。你可能會發現程式碼允許你以不同於上述方式獲取應用程式上下文,但你可能會得到一個指向父上下文的引用,該父上下文不包含服務、控制器等。
總之,Grails 本質上是一個偽裝的 Spring 應用程式。雖然它在表面上隱藏了 Spring,但它提供了一些強大的技術來直接與 Spring 互動。這意味著你可以輕鬆地利用現有的 Java/Spring 庫,並使用一個能夠使大型應用程式比其他方式更易於管理的框架。