领先一步
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 库,并使用一个能够使大型应用程序比其他方式更易于管理的框架。