Apache Ant 编译打包详解与Maven、Gradle区别

Apache Ant 编译打包详解与Maven、Gradle区别

 

JVM生态圈由三大构建工具所统治:

  • Apache Ant带着Ivy
  • Maven
  • Gradel

 

什么是Ant、Maven、Gradle?

Ant with Ivy

Ant是第一个“现代”构建工具,在很多方面它有些像Make。2000年发布,在很短时间内成为Java项目上最流行的构建工具。它的学习曲线很缓,因此不需要什么特殊的准备就能上手。它基于过程式编程的idea。在最初的版本之后,逐渐具备了支持插件的功能。
主要的不足是用XML作为脚本编写格式。 XML,本质上是层次化的,并不能很好地贴合Ant过程化编程的初衷。Ant的另外一个问题是,除非是很小的项目,否则它的XML文件很快就大得无法管理。
后来,随着通过网络进行依赖管理成为必备功能,Ant采用了Apache Ivy。

Ant的主要优点在于对构建过程的控制上。

 

Maven

Maven发布于2004年。目的是解决码农使用Ant所带来的一些问题。
Maven仍旧使用XML作为编写构建配置的文件格式,但是,文件结构却有巨大的变化。Ant需要码农将执行task所需的全部命令都一一列出,然而Maven依靠约定(convention)并提供现成的可调用的目标(goal)。不仅如此,有可能最重要的一个补充是,Maven具备从网络上自动下载依赖的能力(Ant后来通过Ivy也具备了这个功能),这一点革命性地改变了我们开发软件的方式。
但是,Maven也有它的问题。依赖管理不能很好地处理相同库文件不同版本之间的冲突(Ivy在这方面更好一些)。XML作为配置文件的格式有严格的结构层次和标准,定制化目标(goal)很困难。因为Maven主要聚焦于依赖管理,实际上用Maven很难写出复杂、定制化的构建脚本,甚至不如Ant。
用XML写的配置文件会变得越来越大,越来越笨重。在大型项目中,它经常什么“特别的”事还没干就有几百行代码。
Maven的主要优点是生命周期。只要项目基于一定之规,它的整个生命周期都能够轻松搞定,代价是牺牲了灵活性。


在对DSL(Domain Specific Languages)的热情持续高涨之时,通常的想法是设计一套能够解决特定领域问题的语言。在构建这方面,DSL的一个成功案例就是Gradle。

Gradle

Gradle结合了前两者的优点,在此基础之上做了很多改进。它具有Ant的强大和灵活,又有Maven的生命周期管理且易于使用。最终结果就是一个工具在2012年华丽诞生并且很快地获得了广泛关注。例如,Google采用Gradle作为Android OS的默认构建工具。
Gradle不用XML,它使用基于Groovy的专门的DSL,从而使Gradle构建脚本变得比用Ant和Maven写的要简洁清晰。Gradle样板文件的代码很少,这是因为它的DSL被设计用于解决特定的问题:贯穿软件的生命周期,从编译,到静态检查,到测试,直到打包和部署。
它使用Apache Ivy来处理Jar包的依赖。
Gradle的成就可以概括为:约定好,灵活性也高。

---------------------------------------------------------------------------------------------------------------------------

Any with Ivy

Ivy的依赖需要在ivy.xml中指定。我们的例子很简单,只需要依赖JUnit和Hamcrest。

ivy.xml

<ivy-module version="2.0">
    <info organisation="org.apache" module="java-build-tools"/>
    <dependencies>
        <dependency org="junit" name="junit" rev="4.11"/>
        <dependency org="org.hamcrest" name="hamcrest-all" rev="1.3"/>
    </dependencies>
</ivy-module>

代码库 https://github.com/vfarcic/JavaBuildTools

build.xml


<project xmlns:ivy="antlib:org.apache.ivy.ant" name="java-build-tools" default="jar">
 
    <property name="src.dir" value="src"/>
    <property name="build.dir" value="build"/>
    <property name="classes.dir" value="${build.dir}/classes"/>
    <property name="jar.dir" value="${build.dir}/jar"/>
    <property name="lib.dir" value="lib" />
    <path id="lib.path.id">
        <fileset dir="${lib.dir}" />
    </path>
 
    <target name="resolve">
        <ivy:retrieve />
    </target>
 
    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>
 
    <target name="compile" depends="resolve">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="lib.path.id"/>
    </target>
 
    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"/>
    </target>
 
</project>

首先,我们设置了几个属性,然后是一个接一个的task。我们用Ivy来处理依赖,清理,编译和打包,这是几乎所有的Java项目都会进行的task,配置有很多。
运行Ant task来生成Jar文件,执行下面的命令。

ant jar

注:jar  是配置文件中的target的name

 

Maven

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 
http://maven.apache.org/maven-v4_0_0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.technologyconversations</groupId>
    <artifactId>java-build-tools</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>
 
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
        </plugins>
    </build>
 
</project>

执行下面的命令来运行Maven goal生成Jar文件

mvn package

主要的区别在于Maven不需要指定执行的操作。我们没有创建task,而是设置了一些参数(有哪些依赖,用哪些插件...). Maven推行使用约定并提供了开箱即用的goals。Ant和Maven的XML文件都会随时间而变大,为了说明这一点,我们加入CheckStyle,FindBugs和PMD插件来进行静态检查,三者是Java项目中使用很普遍的的工具。我们希望将所有静态检查的执行以及单元测试一起作为一个单独的targetVerify。当然我们还应该指定自定义的checkstyle配置文件的路径并且确保错误时能够提示。更新后的Maven代码如下:

pom.xml

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>2.12.1</version>
    <executions>
        <execution>
            <configuration>
                <configLocation>config/checkstyle/checkstyle.xml</configLocation>
                <consoleOutput>true</consoleOutput>
                <failsOnError>true</failsOnError>
            </configuration>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>findbugs-maven-plugin</artifactId>
    <version>2.5.4</version>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>3.1</version>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>

通过执行下面的命令来运行Maven goal,包括单元测试,静态检查,如CheckStyle,FindBugs和PMD。

mvn verify

 

Gradle

build.gradle         结合了Maven和ant的优点,配置大大减少

apply plugin: 'java'
apply plugin: 'checkstyle'
apply plugin: 'findbugs'
apply plugin: 'pmd'
 
version = '1.0'
 
repositories {
    mavenCentral()
}
 
dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
}

执行下面的命令来得到Gradle在当前配置下能够支持的task列表。

gradle tasks --all

 

Ant的可读性和Maven的简单性

一旦用上了Gradle的DSL,就会发现语法比Ant和Maven更加短小精悍、易于理解。不仅如此,只有Gradle既提供了约定也提供了自定义命令。如果说Maven可以通过Ant task来扩展,这似乎有些滑稽可笑,而且低效,Groovy写的Gradle将其提升了一个层次。

 

Ant详解

(最近有项目使用了所以学习并记录, Maven之前使用过  mvn package

Apache Ant  下载安装 :https://ant.apache.org/bindownload.cgi

配置环境变量:    …………\apache-ant-1.9.2\bin  

使用也简单: 写好项目的build.xml,后就可以用命令  ant xxx    来创建项目(注:xxx是配置文件中的target的name)  

ant 命令

语法元素说明如下:

-help

显示描述ant 命令及其选项的帮助信息

-projecthelp

显示包含在构建文件中的、所有用户编写的帮助文档。即为各个中description 属性的文本,以及包含在元素中的任何文本。将有description 属性的目标列为主目标(Main target),没有此属性的目标则列为子目标(Subtarget)。

-version

要求ant 显示其版本信息,然后退出。

-quiet

抑制并非由构建文件中的echo 任务所产生的大多数消息。

-verbose

显示构建过程中每个操作的详细消息。此选项与-debug 选项只能选其一。

-debug

显示Ant 和任务开发人员已经标志为调试消息的消息。此选项与-verbose 只能选其一。

-emacs

对日志消息进行格式化,使它们能够很容易地由Emacs 的shell 模式(shellmode)所解析;也就是说,打印任务事件,但并不缩排,在其之前也没有[taskname]。

-logfile filename

将日志输出重定向到指定文件。

-logger classname

指定一个类来处理Ant 的日志记录。所指定的类必须实现了org.apache.tools.ant.BuildLogger 接口。

-listener classname

为Ant 声明一个监听类,并增加到其监听者列表中。在Ant与IDE或其他Java程序集成时,此选项非常有用。可以阅读第六章以了解有关监听者的更多信息。必须将所指定的监听类编写为可以处理Ant 的构建消息接发。

-buildfile filename

指定Ant 需要处理的构建文件。默认的构建文件为build.xml。

-Dproperty=value

在命令行上定义一个特性名-值对。

-find filename

指定Ant 应当处理的构建文件。与-buildfile 选项不同,如果所指定文件在当前目录中未找到,-find 就要求Ant 在其父目录中再进行搜索。这种搜索会继续在其祖先目录中进行,直至达到文件系统的根为止,在此如果文件还未找到,则构建失败。

-atuoproxy jdk1.5以上的可以使用代理设置

-nouserlib 运行ant时不使用用户lib中的jar包

-nice 设计主线程优先级

-logfile 使用指定的log日志

-noinput 不允许交互输入

-keep-going, -k 执行不依赖于所有目标

-propertyfile 加载所有属性配置文件 -d 属性文件优先

 

build.xml

<project default="all">

    <property name="pro_a" value="a value" />

    <property name="pro_b" value="b value" />



    <path id="rt.path">

        <pathelement location="${java.home}/jre/lib/rt.jar" />

    </path>



    <target name="all">

        <javac srcdir=".">

            <classpath refid="a.path" />

        </javac>

    </target>

</project>

注意:

● 所有构建文件都要有元素,而且至少有一个 元素。

● 对于 元素的default 属性并不一定需要默认值。

● 构建文件并不一定要被命名为build.xml。不过build.xml 是ant 要搜索的默认文件名。

● 每个构建文件只能有一个 元素。

 

在cmd窗口中进入到当前build.xml目录

复制代码代码如下:

ant

在当前目录下的build.xml运行Ant,执行缺省的target。

复制代码代码如下:

ant -buildfile build-test.xml

在当前目录下的build-test.xml运行Ant,执行缺省的target。

复制代码代码如下:

ant -buildfile build-test.xml clean

在当前目录下的build-test.xml运行Ant,执行一个叫做clean的target。

复制代码代码如下:

ant -buildfile build-test.xml -Dbuild=build/classes clean

在当前目录下的build-test.xml运行Ant,执行一个叫做clean的target,并设定build属性的值为build/classes。

 

ant编译打包、运行工程

<?xml version="1.0" encoding="UTF-8"?>

<!-- name是当前工程的名称,default是默认执行的任务,basedir是工作目录(.代表当前根目录) -->

<project name="HelloWorld" default="run" basedir=".">

    <!-- property类似于程序中定义简单的变量 -->

    <property name="src" value="src"/>

    <property name="dest" value="classes"/>

    <property name="hello_jar" value="helloWorld.jar"/>

    <!--

    target是一个事件、事情、任务, name是当前事情的名称,depends是依赖的上一件或是多件事情

    如果所依赖的事情没有执行,ant会先运行依赖事情,然后再运行当前事情

    -->



    <!-- 初始化 -->

    <target name="init">

        <!-- 建立classes目录 -->

        <mkdir dir="${dest}"/>

        <mkdir dir="temp"/>

        <mkdir dir="temp2"/>

    </target>



    <!-- 编译 -->

    <target name="compile" depends="init">

        <javac srcdir="${src}" destdir="${dest}"/>

        <!-- 设置jvm内存

        <javac srcdir="src" fork="true"/>

        <javac srcdir="src" fork="true" executable="d:\sdk141\bin\javac"

        memoryMaximumSize="128m"/>

        -->

    </target>



    <!-- 建立jar包 -->

    <target name="build" depends="compile">

        <!--

        <jar jarfile="${hello_jar}" basedir="${dest}"/>

        创建一个名称是package.jar文件

        <jar destfile="package.jar" basedir="classes"/>

        -->

        <jar destfile="${hello_jar}" basedir="classes">

            <!-- 向jar包中的main文件中添加内容 -->

            <manifest>

                <attribute name="Built-By" value="${user.name}"/>

                <attribute name="Main-class" value="package.Main"/>

            </manifest>

        </jar>

        <!-- 复制jar文件  todir="复制到目录"-->

        <copy file="${hello_jar}" tofile="${dest}\temp.jar"/>

        <copy todir="temp">

            <!-- 不按照默认方式 defaultexcludes="" -->

              <fileset dir="src">

                <include name="**/*.java"/>

              </fileset>

        </copy>



        <copy todir="temp2">

            <fileset dir="src">

                <and>

                    <contains text="main"/>

                    <size value="1" when="more"/>

                </and>

            </fileset>

        </copy>



        <!-- 移动jar文件 -->

        <move file="${dest}\temp.jar" tofile="temp\move-temp.jar"/>

        <!-- 创建zip -->

        <zip basedir="${basedir}\classes" zipfile="temp\output.zip"/>

        <!-- 创建tgz -->

        <gzip src="classes\**\*.class" zipfile="output.class.gz"/>

        <!-- 解压zip -->

        <unzip src="output.class.gz" dest="extractDir"/>

        <!--替换input.txt内容中的old为new

        <replace file="input.txt" token="old" value="new"/>

        -->

    </target>



    <!-- 运行 -->

    <target name="run" depends="build">

        <java classname="com.hoo.test.HelloWorld" classpath="${hello_jar}"/>

    </target>



    <!-- 清除 -->

    <target name="clean">

        <!-- 删除生成的文件 -->

        <delete dir="${dest}"/>

        <delete file="${hello_jar}"/>

    </target>



    <tstamp>

      <format property="OFFSET_TIME"

              pattern="HH:mm:ss"

              offset="10" unit="minute"/>

    </tstamp>



    <!-- 重新运行 -->

    <target name="rerun" depends="clean,run">

        <echo message="###${TSTAMP}#${TODAY}#${DSTAMP}###"/>

        <aunt target="clean"/>

        <aunt target="run"/>

    </target>

</project>

ant不难,你用它就像是在docs控制台输入命令行一样,只不过ant是将命令行转换为xml的脚本信息,可以进行重复的运行。在一定情况下,提高了效率和重复的工作。

Ant 使用:https://www.w3cschool.cn/ant/3hf51hwb.html   w3cschool 上面也有详细的解释

https://www.iteye.com/blog/liujunhg-1202137    ant 配置文件详解

 

参考:http://technologyconversations.com/2014/06/18/build-tools/

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值