ant、ivy 和 maven

其实对 ant 之类的一直没有正儿八经的看过,但是人在江湖身不由己啊,被逼无奈,还是要了解一下这方面的东西。

ant

原来一直认为 ant 就是 java 世界里面的 make,后来发现其实 ant 和 make 还是有巨大的不同的。虽然两者着重实现的部分是 task 的依赖关系,但是 make 本身不具有可扩展性,具有可扩展性的是 shell 里面的各种命令,这样一来对于不同的任务 make 自己的一些依赖关系就不顶用了,用户需要提供一些生成文件之间的关系或者 target 之间的依赖。对于初学者来说,这个其实就很简单很好用了,可是碰到更为复杂的 task,有时候写起来就比较罗嗦,需要不少 shell 的 trick 帮助调用对应的命令。

ant 呢本身是 java 实现的,所有的 task 都是对应某个 java 的类,配置通过 XML 表达,我们知道 XML 的表述能力比较强,只要符合某些要求的 java 类都可以通过 ant 引入到其配置文件里面作为新的一种 task 来进行调用,这意味着用户能通过 Java 程序实现一些原先需要用 shell 的 trick 实现的任务。另外,由于 JVM 上脚本语言的成熟,类似 groovy 等语言也可以引入到实现 ant task 或辅助实现的过程中来。我们下面可以看看 ant 的 task 究竟是什么。下面是一个再简单不过的程序

public class HelloWorld {
    public void execute() {
        System.out.println("Hello World");
    }
}

配上我们老土的 build.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="MyTask" basedir="." default="use">
  <target name="compile">
    <javac srcdir="." includes="*.java" includeantruntime="true" />
  </target>

  <target name="jar" depends="compile">
    <jar basedir="." includes="*.class"
         destfile="${ant.project.name}.jar" />
  </target>

  <target name="use" description="Use the Task" depends="jar">
    <taskdef name="helloworld" classname="HelloWorld"
             classpath="${ant.project.name}.jar"/>
    <helloworld/>
  </target>
</project>

之后执行 ant 居然成了…

$ ant
Buildfile: /home/someone/MyTask/build.xml

compile:

jar:
      [jar] Building jar: /home/someone/MyTask/MyTask.jar

use:
[helloworld] Hello World

BUILD SUCCESSFUL
Total time: 0 seconds

看起来非常神奇,因为我们并没有 import 任何 ant 的东西或者实现某些 interface,为啥能 call 我们的 execute 呢?其实也很简单,reflection!但是实际写一个好的 task 势必会用到 ant 提供的不少信息,有比如处理含有 ${} 的字符串需要进行替换等等,这时我们往往继承 org.apache.tools.ant.Task,通过 getProject 获得 org.apache.tools.ant.Project,这样就能访问一些 project 的信息(即 xml 里面的配置)。每个 task 都可以看成是一个 POJO,通过 setter 我们可以为这个 task 设置属性(支持 java.lang 里面那些类型),这样对应在 XML 里面我们写

<helloworld message="hello"/>

对应在 HelloWorld 里面我们就应该提供 setMesssage 方法了。如果希望通过子节点提供信息,如

<helloworld>
  <message>hello</message>
  <message>world</message>
</helloworld>

我们就需要实现 addMessage 方法,注意这里传入的字符串不会被替换 ${},我们需要调用 getProject ().replaceProperties () 进行替换。如果是 nested element,我们需要提供 createXxx 方法,这样就能在一个 POJO 里面嵌入比较复杂的结构了。比较有用的 ant 运行参数是 -verbose 和 -debug。

想知道 ant 自己带了哪些 task 的话可以看这里,有了这些基本的 task 和对应的属性说明,我想简单的 build.xml 不成问题。剩下的就是怎么做复杂的 task 了。其实有了 taskdef,我们获得的只是引入新的 task 的能力,我们还需要类似程序的控制结构:

  • target 可以用 if/unless 属性(值为 boolean)来进行条件执行
  • 循环 ant 本身没提供,但是可以 taskdef 一些外部别人实现的概念,比如这里有一些。
  • debian 里面的 ant 包括三个主要的 jar,ant-optianl 里面提供了一些对 commons 里面一些 package 的支持(还有 check style),ant-contrib 里面有一些 3rd party 的,如 if/foreach、服务器等。

最后一些基本的概念是和 IO 有关系的,fileset 用来表述一个文件集合,path 用来描述一个路径。通过这两个类,我们在 task 里面就能接受外部指定的文件和路径了。

有了这样一些 task 离项目管理还需要一些“逻辑”,比如大的概念如 compile、package、test、check bug、coding style、deploy、execute,细化到每个概念,可能又包含一些子概念,一直到我们一些具体的 task,项目做的多了,这些公用的逻辑就会被整理出来,单独放在一个 XML 里面,而项目的 build.xml 直接包含这个 XML,并对其某些属性进行定制就 ok 了。这也就是为什么 ant 一度是不少项目默认的 build system 的原因吧。

有了这些基本的概念之后我们还知道,如果 groovy 的程序需要和 Java 共存在一个项目中,我们就需要为 groovy 之类的提供他们的 task(幸运的是 groovy 自己的确带了两个 task,一个叫 groovy 一个叫 groovyc)。有这些之后就需要将这些 task 整合到现有项目逻辑里面去,比如原先的 compile 可能只包括 javac,现在加入 groovyc 也许就行了。

ivy

上面说了半天 ant,那么到底什么是 missing 的呢?嗯,那就是作为编译系统,需要解决待编译程序与外部依赖程序/库之间的关系。也就是通常通过 classpath 传递的那些 jar 如何与项目本身关联上?ivy 实际上是 ant 的 task,它着重解决的就是依赖关系。下面说一下大致怎么用 ivy:

  • 写一个 ivy.xml 里面描述项目依赖的 jar,这类似 pom.xml 里面关于 dependency 那一节的内容
  • 在 build.xml 里面添加一个 resolve 的 target,调用 ivy:retrieve 获得这些 jar
  • 完了…

其实 ivy 偷偷用了 maven 的 repository,像 python 等语言一样,java 自从有了 maven 的 respository,大家不再费事去到处搜刮一些 jar 等到写 code 的时候堆上去了(可惜像 C/C++ 一直很难找到这样的 repository)。

与 maven 的比较

其实 ant 或者 ivy 本身都不足以与 maven 比较,因为实现的功能都只有其一部分。但是和起来的话,看到的评论主要分两个:

  • maven 从对用户的便利性来说可能是非常优秀的,通过 archetype 也能进行定制,和 eclipse 等 IDE 整合也很好了
  • ant + ivy 会让某些情形的应用配置更加 flexible,据说 maven2 实现那些依赖什么的还是挺费事的,通过 ivy 直接盗用 maven 工作者的结果不晓得算不算好…
  • 有的公司可能 java 的迁徙做的早,把自己的 java library 放在自己的 repository 里面,通过修改 maven 默认的 repository 就能控制员工写程序使用的 library 了
  • 有的做的可能不是那么好,一方面是为了自己定制的 build 系统和 deploy 系统,于是还沿用 ant,这时管理 jar 的任务可以用定制过的 ivy 等来解决

好了,咱可以干活了…

——————
And Abimelech called Isaac, and said, Behold, of a surety she is thy wife: and how saidst thou, She is my sister? And Isaac said unto him, Because I said, Lest I die for her.

Advertisements
ant、ivy 和 maven

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s