领先一步
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 库,并使用一个框架,该框架使得大型应用程序比没有它时更易于管理。