科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道让开发自动化: 使用 Raven 构建 Java 项目

让开发自动化: 使用 Raven 构建 Java 项目

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文演示了 Raven 的强大功能,其美妙之处在于,您可以在构建脚本中利用 Ruby 语言的强大功能和灵活性。Raven 是否会成为构建 Java 项目的流行平台不是我能决定的,但是我相信 Raven 是在推动业界朝着正确的方向前进。特别是,Raven 通过一种功能全面的命令式编程语言(而不是像 XML 那样的说明性语言)支持基于依赖的任务。尝试一下,您就会明白我的意思。

作者:builder.com.cn 来源:来源网站 2007年11月23日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

我手头上有一个 Java 项目,在过去几年的时间里,我小心翼翼地为之维护一个 Ant 构建脚本。Ant 能够执行大量任务,这一点我十分欣赏;然而,我常常发现,Ant 脚本的 XML 语法编写起来有些麻烦。而且,在 可表达性 方面,Ant 的 XML 部分还存在限制。实际上,当我发现自己需要更高程度的灵活性(例如在条件逻辑方面)时,我常常不得不在 Ant 的 script 任务中编写(例如使用 Groovy)定制任务或嵌入式逻辑。

告别表达乏力

数年前,当我在寻找可表达性更强的软件构建工具时,我听说过 Rake。Rake 是用于使用功能全面的 Ruby 编程语言构建软件的一种域特定语言。通过 Rake,我可以轻松获得正在寻找的可表达性。例如,我不必编写定制任务,因为 Rake 构建脚本是 Ruby(而不是 XML);因此,如果我需要某种条件逻辑,那么很容易在需要的地方编写这种逻辑。而且,Rake 采用基于依赖的任务系统,这类似于 Ant 及其前辈 make 中的任务系统。例如,如果输入 rake deploy,Rake 将调用之前设置的依赖任务,例如编译,运行测试等等。而且 Rake 非常智能,它只运行一次依赖性任务(就像 Ant 一样)。

对于大多数 Java 项目来说,Rake 本身并不能提供多大帮助;然而,一个相对较新的项目 Raven 将 Rake 的功能和可表达性与用于构建 Java 应用程序的特定任务结合起来。有了 Raven,Java 开发人员就有了一个真正可行的构建平台,该平台可提供特定于 Java 的特性,例如使用 javac 进行编译以及使用 jarwar 归档二进制文件,同时还拥有 Ruby 编程语言的丰富的可表达性。

什么是 DSL?
域特定语言(DSL)是专门为特定任务设计的编程语言。 Java 语言和 Ruby 是通用的编程语言,而 Ant 和 Rake 是专用于构建软件的 DSL。Rake 被认为是一种内部 DSL,因为它是用 Ruby 编写的,并且可以使用 Ruby 进行扩展。而 Ant 是一种外部 DSL,因为它首先被解析,然后在另一种语言中执行(也就是说,首先解析 XML,然后通过 Java 程序来运行)。

Raven 是 Rake,Rake 是 Ruby

在将 Raven 用于 Java 项目之前,理解 Raven 与 Rake 之间的关系会有所帮助。图 1 显示了 Raven 的一个逻辑图,可以看到,Raven 使用 Rake、RubyGems 和 Ruby。相应地,在使用 Raven 时,可以使用本地 Rake 任务。而且,还可以在 Raven 脚本中使用 Ruby。RubyGems 是类似于 CPAN、RPM 或 APT 的一个包管理器,用于下载必需的 Ruby 包(以及 Java jar)和任何依赖包。


图 1. Raven 的逻辑图
Raven 的逻辑架构

虽然还不确定 Raven 是不是构建 Java 项目的最佳 平台,但是可以发现,在转向更自然的编程语言方面,Raven 提供了一个简单而强大的组合。要是让我来说,单凭不必依赖 XML 就可构建 Java 项目这一点,足以使 Raven 获得更多关注。





回页首


下载和安装 Raven

有两种方法可安装和配置 Raven,第一种方法是 Ruby 方法,第二种方法则更倾向于 Java,即使用 JRuby。我推荐 Java 方法,因为这样更容易配置。安装 Raven 和使之运行需要以下步骤:

  • 下载 Raven/JRuby 发行版(参见 参考资料)。

  • 将文件解压到工作站上的一个位置。

  • 创建环境变量 JRUBY_HOME

  • JRUBY_HOME/bin 添加到 PATH 环境变量中。

  • 打开一个命令提示符,输入 jruby -version,以检查安装情况。如果完全安装成功,那么在命令窗口中应该看到类似于 ruby 1.8.5 (0) [java] 的内容。

开始使用 Raven

当然,下载和安装 Raven 只是小菜一碟。真正有趣的是在创建构建脚本时 Raven 具有的灵活性。在 Raven 术语中,构建文件被称作 Rakefiles,它们有一个简单的格式。实际上,如果您用 Ruby 编写过程序(或者见过 Ruby 代码),那么这些文件看上去会很熟悉。这正是 Raben 的美妙之处:它就是 Ruby — 只不过在其中添加了一些特殊的词。

为了尽快使用 Raven ,毫无疑问,首先我要执行最基本(但是也很重要)的任务,即编译。图 2 中的目录结构表示了我的 Java 项目的布局。如果知道第三方库和源代码所在的位置,就能更快上手了。


图 2. 现有 Java 项目的目录结构
现有 Java 项目的目录结构

注意图 2 中的 lib 结构,第三方 JAR 就在其中。在开始编译之前,必须创建一个路径,使用 Raven 做这件事再容易不过了,因为它支持通过它的 dependency 任务(实际上是 Raven 提供的一个名为 dependency 的 Ruby 方法)创建类路径,如清单 1 所示:


清单 1. 使用 Raven 创建类路径

require 'raven'
require 'rake'

dependency 'deps' do | task |
  task.libs = Dir.glob('lib/**/*.*')  
end 

根据清单 1 中的定义,deps 依赖任务使用 Dir 类和 glob() 方法包括 lib 目录中的所有库。还可以使用这个依赖任务(通过 RubyGems)从一个储存库中下载 JAR(这类似于 Maven 的依赖管理机制)。

在清单 1 中,我特意在路径中包括了 lib 目录中的所有东西。我将这个任务命名为 deps,在尝试编译任何文件之前,都可以显式地执行该任务,如清单 2 所示:


清单 2. 编译很容易

javac 'compile' => 'deps' do |task|
  task.build_path << "src"
end

可以看到,我通过 Raven 的 javac 任务执行编译。该任务名为 compile,它对清单 1 中的 deps 任务存在依赖。符号 => 的意思是,Raven 将在当前任务之前 运行该操作符右边的任务(这很像 Ant 中 target 元素的 depends 属性。

魔力就发生在 javac 任务的 doend 之间。默认情况下,javac 任务使用 "src/main/java" 作为 build_path 的默认值。但是,由于我的 Java 项目并没有遵循这个惯例(还记得 图 2 吗?),我需要修改 build_path 属性,在这里它应该为 src,因为源代码就在其中。

Raven 只是用于 Maven 的 Ruby 吗?

您可能会认为 Raven 只是 Ruby 版的 Maven,但是这么说并不准确。虽然在默认的命名惯例和依赖管理方面有相似之处,但 Raven 的创始人的解释是,这样做更容易。

为了测试 Raven 脚本,需要打开一个命令提示符,然后输入:rake compile。编译后会生成 .class 文件,这些文件被放到一个名为 target/classes 的目录中,该目录是由 javac Raven 任务自动生成的。

少就是多

这里要弄清楚一点。我不必编写很多代码就可以完成编译,因为 Raven 在幕后处理了一些事情,例如创建 target/classes 目录并将生成的类文件复制到这个位置。实际上,您可能已经忘了 清单 1清单 2 中对应的 Ant 脚本是什么样子。这里提示一下,清单 3 显示了一个典型的使用 Ant 构建脚本的编译:


清单 3. 使用 Ant 编译 Java 源代码

<?xml version="1.0" encoding="iso-8859-1"?>
<project name="compile-code" default="all" basedir=".">
...
  <target name="compile-src">
    <mkdir dir="${classes.dir}"/>
    <javac destdir="${classes.dir}" debug="true">
      <src path="${src.dir}" />
      <classpath refid="project.class.path"/>
    </javac>
  </target>
<project>

将清单 3 与 清单 1清单 2 比较,可以看出一些明显的不同。Raven 不但废除了 XML,而且还假定一些基本的属性,使您在定义任务时需要指定的东西更少。而且,如清单 2 所示,如果有必要,Raven 允许重写假定的属性。

虽然从比较的角度来看清单 1 和清单 2 确实比较有趣,但编译只是构建脚本的有趣之处的一个开始。让我们来看一个更有趣的特性:打包 Java Web 应用程序。





回页首


简单的 war 文件生成

Web 归档(Web Archive,WAR)文件用于打包 Web 应用程序,其中包含诸如 servlet、第三方库和图像之类的各种资源。这些归档文件使用标准的目录命名模式,并且只接受某些文件,例如 web.xml(该文件映射 servlet 名称和其它配置方面),放置在 WEB-INF 目录中。

Raven 使 WAR 文件的创建变得非常简单。在清单 4 中,我以 'brewery.war' 作为名称使用 war 任务,默认情况下,该任务创建一个具有相同名称的 WAR 文件。webapp_dir 的默认位置是 src/main/webapp,但是由于我的目录结构不同于 Raven 的假定,因此需要通过 task.webapp_dir = 'src/web' 行对此进行修改。


清单 4. 创建部署到 Web 容器的 WAR

war 'brewery.war' => ['clean', 'compile', 'java-doc'] do |task|
  task.webapp_dir = 'src/web'
end

注意,在创建 WAR 文件之前,Raven 必须首先运行 clean 任务,接着运行 compile 任务,然后再运行一个任务来创建一些文档。在这些任务成功运行之后,Raven 可以创建一个归档文件,您将看到,这里需要输入的东西很少。实际上,如果我的项目遵循 Raven 假定的默认目录布局的话,那么除了那些依赖任务之外,不再需要编写任务东西(也就是说,不需要 doend 之间的代码!)。

不管您信不信,Raven 就这么简单 — Raven 的 war 任务处理目录的创建,文件的放置,以及 war 文件的生成。非常高效,不是吗?

是 Raven、Rake 还是 Ruby?
所有都是!Rake 是使用 Ruby 构建项目的一种 DSL。Raven 则使用 Rake 来为构建 Java 项目提供特定于 Java 的功能。就像 Rake 一样,通过 Raven 可以在构建脚本中充分使用 Ruby 编程语言。

轻松地生成文档

生成项目文档对于向团队成员宣传有用信息通常会有所帮助。如果别人计划使用您正在编写的框架代码或实用程序,那么您最终需要发布 Javadoc,这些 Javadoc 是描述相关源代码中的类、方法和公共实例变量的一些 HTML 文件。

通过 Raven,可以很快地利用 Javadoc 机制生成文档,如清单 5 所示:


清单 5. 使用 Raven 生成 JavaDoc 文档

javadoc 'java-doc' => 'deps' do |task|
  task.build_path << "src"
end

请再次注意,由于我的项目没有遵循 Raven 假定的模型,因此必须修改 javadoc 任务的 build_path 属性。此外,该任务依赖于 deps 任务(在 清单 1 中)来包括所有类引用。

至此,您大概已经意识到,如果项目遵循 Raven 假定的布局,那么构建脚本甚至比我的还要简单!





回页首


更多特性!

虽然我只谈到了 Raven 中提供的一部分特性,但是还可以用这个创新的构建平台做更多的事情。特别地,Raven 为使用 RubyGems 机制处理构建依赖(即第三方库)提供了广泛的支持,RubyGems 在构建时自动下载版本化的二进制文件,而不是引用共享驱动。RubyGems 以类似于 Maven 或 Ivy 的方式处理第三方库。

除了 RubyGems 之外,Raven 还可以运行 JUnit 测试,构建一般的 JAR 文件,并且还可以清理目录。表 1 列出了 Raven 中一些较流行的、可方便构建 Java 项目的任务:


表 1. 流行(并且有用)的 Raven 任务

Raven 任务 描述
javac 编译 Java 源文件,默认情况下将生成的类文件放入 target/classes 目录中。
jar 生成一个 JAR 文件,该文件通常是 .class 文件的一个集合。
war 生成一个可部署到 Java Web 容器的 Web 应用程序归档文件。
javadoc 根据源代码生成 Javadoc。
junit 执行 JUnit 测试。
jar_source 根据 Java 源文件创建一个 JAR 文件。
gem_wrap_inst 将 JAR 文件转换到 RubyGem,然后将该文件安装到一个存储库中。

随着 Raven 的成熟,表 1 中的列表会进一步扩大。此外,如果 Raven 中还缺少某种您需要的功能,您完全可以自己编写它!

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章