領先一步
VMware 提供培訓和認證,助您加速前進。
瞭解更多在 SpringSource 關於 Groovy & Grails 的培訓課程中,我們強調 Grails 是站在巨人的肩膀上。其中一個巨人就是 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 裝配到您的 Service(以及所有其他核心 Grails artifact)中同樣簡單直接:宣告一個與您想要的 bean 同名的屬性。例如,假設我想在另一個 Service(或者控制器)中使用 "auditReportService" bean。我可以這樣裝配:
class MyService {
def auditReportService
...
}
我相信您會同意這非常簡單。這是 Spring 自動裝配的一個例子。即使您為屬性指定了型別,Grails 也會按名稱裝配 bean。
Service 的另一個有用特性是它們預設是事務性的。這使得它們成為抽象資料訪問併為您的應用程式構建健壯架構的絕佳方式。典型的方法是為您的 Service 建立不同的“閘道器”:HTML UI、XML REST 介面、透過 RMI 進行遠端呼叫等,它們都呼叫您的 Service。
最後一點:我說 Grails 會將您的 Service 例項化為單例 bean,但您可以為每個 Service 更改此行為。只需在您的 Service 類中新增一個靜態scope屬性,如下所示:
class MyService {
static scope = "request"
...
}
正如您所見,使用 Service 時,您幾乎不費吹灰之力就能獲得 Spring 的許多主要好處。這很棒,但是如果您有現有的類想要變成 bean 怎麼辦?也許您是用 Java 編寫的,或者它們打包在一個 JAR 檔案中。使用純粹的 Spring,您需要手動配置它們。幸運的是,您可以在 Grails 中做同樣的事情。
我必須說,我不再喜歡編寫 XML 了,所以我更喜歡另一種 bean 定義格式:Grails 的 Spring Bean DSL。這是一個在grails-app/conf/spring/resources.groovy:
beans = {
reportGenerator(org.example.XmlReportGenerator)
}
中定義報告生成器 bean 的一個非常簡單的例子。定義以 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 Service 客戶端,而對於所有其他環境,我們使用一個記憶體中的虛擬 Service。您還可以看到,可以將一個字面量 Map 賦值給一個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,或者一個團隊開發了一些 Spring MVC 控制器,您希望將其放入您的 Grails 應用程式中,這會很有幫助。
正如您所見,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。您可能會發現一些程式碼允許您透過不同於上述詳細介紹的方式獲取應用程式上下文,但您最終可能會獲得對父上下文的引用,該上下文不包含 services、controllers 等。
總而言之,Grails 本質上是一個偽裝的 Spring 應用程式。雖然它隱藏了 Spring,使其不顯眼,但它確實提供了一些強大的技術可以直接與 Spring 互動。這意味著您可以輕鬆利用現有的 Java/Spring 庫,並使用一個框架,該框架使得大型應用程式比沒有它時更易於管理。