Grails 和 Maven:一段不便的结合

工程 | Dave Syer | 2007年7月14日 | ...

引言

Grails 似乎发展势头越来越强劲,而且看来它确实“站稳了脚跟”,正如他们所说。我对将它的应用范围稍微扩展到 Web 应用领域之外很感兴趣。如果你了解我在 Spring Batch 方面的工作,你大概就能猜到这可能会把我带向何方。但在这篇文章中,我只想分享一些我在 Grails 应用的基本、底层部署和构建方面的一些经验。

我对 Maven 2 既爱又恨,我正在学习喜欢 Grails,但不幸的是,两者并不能很好地协作。如果能看到更紧密的集成将会非常棒。Maven 并不总是我们想要的样子,但有些方面确实让它很有价值。它是一种标准(无论你爱它还是恨它),所以当我从某个地方下载一个项目时,我已经知道如何构建它,它的依赖是什么,以及文档在哪里。Grails 也有一些相同的特性,事实上它包含了自己基于 Groovy 脚本 Ant 的相当复杂的构建工具。也许存在一个中间道路,让我们能够兼得两者的优点?

我也知道该领域的一些其他活动,希望我们能围绕某个方向 объединять 一下(也许可以从本论坛和 Grails JIRA 的讨论中获得启发)。例如,请看 Frederick Verbist 的博客和 Arnaud Heritier 的 maven 集成项目(目前刚刚起步)。Grails 团队传统上对 Maven 印象不佳(例如,参见此处),但我与 Graeme Rocher 聊过,他对建议持开放态度,所以我希望我们在这里能取得一些进展。

使用 Maven 为 Grails 构建原型依赖管理

本着朝着 maven 集成迈出简单步骤的精神,我附上了一组 poms,它们(大致)描述了我在 Grails 0.5.6 中了解到的 Grails 依赖结构。如果您遇到问题,请忽略或更改 Spring 版本号 - Grails 0.5.6 使用 Spring 2.0,但我正在进行的项目需要 2.1。Graham 说 Grails 可能无法与更高版本的 Spring 正常工作,因此您的实际情况可能有所不同。这就是 Maven 的美妙之处,对吧?您可以明确地、传递地看到项目依赖,并且可以以您控制的方式调整它们,以满足您自己的需求和对风险的承受能力。

Maven 用户附注:依赖插件比以前工作得更好了,您可以使用“mvn dependency:tree”打印出依赖树。这仅适用于全新的插件,因此请确保 apache-snapshots 仓库在您的插件仓库中。


<pluginRepositories>
	<pluginRepository>
		<id>apache-snapshots</id>
		<url>http://people.apache.org/maven-snapshot-repository</url>
	</pluginRepository>
</pluginRepositories>

这比必须构建整个站点并查看依赖报告方便得多,而我以前经常这样做。

一个 POM,一个 POM,我的王国换一个 POM...

当一个神志不清的 Maven 用户首次面对 Grails 项目并试图理解它如何协同工作时,这是他的呐喊。希望我们在此能展示如何安抚这位可怜的神志不清的个体。为此,我们将介绍一些简单的步骤,为现有 Grails 项目创建一个 Maven 项目。

在随附的沙盒存档中,有三个 poms,每个都在自己的项目中

  • base = 与 Web 应用无关的依赖项的基础 POM。我在这方面相当宽松(例如包括 Spring Weblfow)。目标是仅凭这些依赖项就应该能够启动 grails console。
  • web = 为 Web 应用创建 WAR 文件所需的额外依赖项。这可能在一定程度上取决于平台,但此处包含的依赖项将在 Servlet 2.4 容器(如 Jetty 5.1,这是 Grails 传统上使用的)中工作。
  • launch = 仅用于在独立或开发环境中启动 Web 应用的 Jetty 和 JSP 依赖项

要安装 Grails poms,您无需手动将任何工件添加到本地仓库。还有一些“奇怪的”(我在任何标准的公共仓库中都找不到),我已经将它们包含在“spring-ext”仓库中(在 pom 中定义)。如果您连接到互联网,它应该可以直接工作。

运行样本的先决条件

您需要 Maven (2.0.*) 和 Grails (0.5.6) 来运行样本应用。我使用的是 Maven 2.0.7。“grails”和“mvn”启动脚本需要放在您的 PATH 中,并且您需要定义 GRAIL_HOME 环境变量来运行 Grails(标准安装程序)。

测试项目

还有一个测试项目,它使用上面的 poms 来管理一个 Web 应用。我决定坚持使用 Grails 的目录布局。Graham 告诉我,web-app/WEB-INF 中几乎所有“可变”内容都计划在 Grails 1.0 中移除,所以我认为使用 Grails 规定的结构是最好的前进方向(最不容易脆弱,易于其他 Grails 开发者理解)。

从 Grails 命令行启动

$ cd test
$ mvn package
$ grails run-app

要向测试项目添加额外的依赖项,只需将它们添加到 pom 中并重复此操作(或在 Eclipse 中什么都不做,见下文)。Maven 是不是很棒?

请注意,在项目 pom 中,Grails 依赖项的范围是 scope=provided。这意味着它们会包含在 Maven 和 Eclipse 的 classpath 中,但不会包含在任何 Maven 打包中(如果已实现)。

仅限 Eclipse 用户

测试项目还包括 Eclipse 项目工件 - 使用 Maven Eclipse 扩展以获得最佳结果 (http://m2eclipse.codehaus.org/update-dev/)。使用此 Eclipse 扩展,您将能够在工作空间中处理其他 Maven 工件项目,如果它们是 Grails 项目的依赖项,它们将被自动添加到 classpath 中,并在您进行更改时动态更新。

如果您不使用 Maven Eclipse 扩展,那么您可能可以使用 Eclipse Maven 插件(也称为 maven-eclipse-plugin)。使用“mvn eclipse:eclipse”更新 .classpath 并刷新,然后应该就可以了,但无法自动与 Eclipse 其他项目中的更改同步。

您需要先从命令行执行一次“grails package”(仅执行一次)

$ cd test
$ grails package

这将为您生成一个 web.xml,并复制和过滤 grails-app/conf 中的一些属性文件。显然,长期的前景是 web.xml 将是 web-app/WEB-INF 中唯一生成的文件(这样每个人的源代码控制系统中就只有一个 svn:ignore)。

在 Eclipse 中,您可以导入测试项目。然后可以运行...并从 Java 应用中选择“test”启动器。您可以调试,并且可以动态更改代码,无论是 Grails 应用本身还是其依赖的项目中的代码。

下一步

我附带的工具还有一些缺失/不舒服的地方。它们仍在很大程度上处于开发中。如果有人试用它们,无疑会提出改进的建议。请在此处或在 Grails JIRA 上发帖。

以下是一些已知问题或令人恼火之处

Grails 打包中的重复 Jar

Grails 核心的一些依赖项可能与 poms(Grails poms 或项目 pom)中的依赖项不同或名称不同。当您执行“grails package”时,它会将 GRAILS_HOME/lib 中的 jar 文件复制到 web-app/WEB-INF/lib 中,并且无法阻止重复。例如,只要 Grails 不使用完整的 jar 名称,您就会在 WEB-INF/lib 中看到重复项。

这个问题因为 Maven 依赖插件目前不允许我们排除 scope=provided 的依赖项而更加复杂,因此当您执行“mvn package”时,所有 Grails 依赖项最终都会出现在 ./lib 中。这对于 Grails 开发者来说并不方便,因为它们通常是从 GRAILS_HOME/lib 中复制的。理想情况下,这种冲突将在我们真正实现 Maven-Grails 集成之前得到解决。

缺少其他 Maven 生命周期阶段

这个简单的演示为 Grails 提供了一个 clean 和一个 package 生命周期增强。我们希望能够使用 Maven 为我们完成更多的开发和持续集成工作。

例如,我们希望从 Grails 项目布局构建一个 WAR 文件。用 Ant 和 Maven 实现这一点不会太难。理想情况下,它应该作为 Maven 插件实现——这与 Arnaud 的项目非常相似,所以我希望他能取得一些进展,同时也希望他能从这里的经验中学习。

其他有用的生命周期阶段也缺失了。例如,样本中无法通过 Maven 驱动测试。

Grails 打包周期

Grails 和 Maven 各有其自己的“打包”周期。通常 Grails 的打包只需发生一次(在两次 clean 之间),但这仍然很麻烦,必须记住要执行它。

Eclipse 的 Groovy 插件

在 .groovy 源代码中有语法高亮很好,但除此之外,Groovy 插件似乎只会碍事。这与 Maven 或 Grails 都没有关系,但已知它会给其他 Grails Eclipse 用户带来问题。例如,如果您编辑控制器或服务,很可能会看到一个令人不快的警告消息,询问您是否要终止应用程序。Groovy 插件检测到了更改,而 Eclipse 无法处理 classpath 的更改。但 Grails 可以,所以通常您可以点击“继续”按钮。但并非总是如此。在项目属性中关闭 Groovy 编译是安全的,但这会失去对非 grails-app 类的动态编译。
附件再次附上:点击此处

订阅 Spring 新闻通讯

订阅 Spring 新闻通讯,保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速前行。

了解更多

获取支持

Tanzu Spring 通过简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看全部