Ant vs Maven vs Gradle

2023/05/24

1. 概述

在本文中,我们将探讨主导JVM生态系统的三种Java构建自动化工具:Ant、Maven和Gradle

我们将介绍它们中的每一个,并探讨Java构建自动化工具是如何演变的。

2. Apache Ant

一开始,Make是唯一可用的构建自动化工具,超越了本土解决方案。Make自1976年以来一直存在,因此,它在早期Java时代用于构建Java应用程序。

但是,C程序的许多约定并不适合Java生态系统,所以随着时间的推移,Ant成为了一个更好的选择。

Apache Ant(“Another Neat Tool”)是一个Java库,用于自动化Java应用程序的构建过程。此外,Ant还可用于构建非Java应用程序。它最初是Apache Tomcat代码库的一部分,并于2000年作为独立项目发布。

在许多方面,Ant与Make非常相似,而且它非常简单,因此任何人都可以在没有任何特定先决条件的情况下开始使用它。Ant构建文件是用XML编写的,按照惯例,它们被称为build.xml。

构建过程的不同阶段称为“目标”。

下面是一个带有HelloWorld主类的简单Java项目的build.xml文件示例:

<project>
    <target name="clean">
        <delete dir="classes"/>
    </target>

    <target name="compile" depends="clean">
        <mkdir dir="classes"/>
        <javac srcdir="src" destdir="classes"/>
    </target>

    <target name="jar" depends="compile">
        <mkdir dir="jar"/>
        <jar destfile="jar/HelloWorld.jar" basedir="classes">
            <manifest>
                <attribute name="Main-Class"
                           value="antExample.HelloWorld"/>
            </manifest>
        </jar>
    </target>

    <target name="run" depends="jar">
        <java jar="jar/HelloWorld.jar" fork="true"/>
    </target>
</project>

这个构建文件定义了四个目标:clean、compile、jar和run。例如,我们可以通过运行以下命令来编译代码:

ant compile

这将首先触发目标clean,这将删除“classes”目录。之后compile目标会重新创建目录,并将src文件夹编译进去。

Ant的主要优点是它的灵活性,Ant不强加任何编码约定或项目结构。因此,这意味着Ant需要开发人员自己编写所有命令,这有时会导致难以维护的庞大XML构建文件。

由于没有约定,仅仅知道Ant并不意味着我们会很快理解任何Ant构建文件。习惯一个不熟悉的Ant文件可能需要一些时间,与其他较新的工具相比,这是一个缺点。

起初,Ant没有对依赖管理的内置支持。然而,随着依赖管理在后来的几年成为必须的,Apache Ivy被开发为Apache Ant项目的子项目,它与Apache Ant集成,并遵循相同的设计原则。

但是,由于没有内置的依赖关系管理支持以及使用无法管理的XML构建文件时遇到的挫折,Ant最初的局限性导致了Maven的创建。

3. Apache Maven

Apache Maven是一种依赖管理和构建自动化工具,主要用于Java应用程序。Maven继续使用XML文件,就像Ant一样,但使用的方式更易于管理,这里的游戏名称是约定优于配置。

虽然Ant提供了灵活性并要求从头开始编写所有内容,但Maven依赖于约定并提供预定义的命令(目标)

简而言之,Maven使我们能够专注于我们的构建应该做什么,并为我们提供了执行此操作的框架。Maven的另一个积极方面是它为依赖关系管理提供了内置支持。

Maven的配置文件包含构建和依赖管理指令,按照惯例称为pom.xml。此外,Maven还规定了严格的项目结构,而Ant也提供了灵活性。

下面是一个pom.xml文件的示例,该文件用于与之前的HelloWorld主类相同的简单Java项目:

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.tuyucheng.taketoday</groupId>
    <artifactId>mavenExample</artifactId>
    <version>1.0.0</version>
    <description>Maven example</description>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

但是,现在项目结构也已经标准化并符合Maven约定:

+---src
|   +---main
|   |   +---java
|   |   |   \---cn
|   |   |       \---tuyucheng
|   |   |           \---taketoday
                        \---maven
                            ---HelloWorld.java
|   |   |                   
|   |   \---resources
|   \---test
|       +---java
|       \---resources

与Ant不同,无需手动定义构建过程中的每个阶段。相反,我们可以简单地调用Maven的内置命令。

例如,我们可以通过运行以下命令来编译代码:

mvn compile

正如官方页面上所指出的,Maven的核心可以被认为是一个插件执行框架,因为所有工作都是由插件完成的。Maven支持范围广泛的可用插件,并且每个插件都可以额外配置。

其中一个可用的插件是Apache Maven Dependency插件,它有一个copy-dependencies目标,可以将我们的依赖项复制到指定的目录。

为了展示这个插件的实际效果,让我们将这个插件包含在我们的pom.xml文件中,并为我们的依赖项配置一个输出目录:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>target/dependencies
                        </outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

这个插件将在package阶段执行,所以如果我们运行:

mvn package

我们将执行此插件并将依赖项复制到target/dependencies文件夹。

还有一篇关于如何使用不同的Maven插件创建可执行JAR的现有文章。此外,要获得详细的Maven概述,请查看有关Maven的核心指南,其中探讨了Maven的一些关键功能。

Maven变得非常流行,因为构建文件现在已经标准化,并且与Ant相比,维护构建文件所花费的时间要少得多。然而,尽管比Ant文件更标准化,但Maven配置文件仍然倾向于变得庞大和笨重。

Maven的严格约定的代价是不如Ant灵活,目标定制非常困难,因此与Ant相比,编写定制构建脚本要困难得多。

尽管Maven在使应用程序的构建过程更容易和更标准化方面做出了一些重大改进,但由于不如Ant灵活得多,它仍然需要付出代价。这导致了Gradle的诞生,它结合了两个世界的优点:Ant的灵活性和Maven的特性。

4. Gradle

Gradle是一种依赖管理和构建自动化工具,它是基于Ant和Maven的概念构建的

关于Gradle,我们首先要注意的最重要的事情之一是它不使用XML文件,这与Ant或Maven不同。

随着时间的推移,开发人员对拥有和使用特定领域的语言越来越感兴趣-简单地说,这将允许他们能够使用为特定领域量身定制的语言来解决特定领域中的问题。

这是Gradle采用的,它使用基于GroovyKotlin的DSL,这导致了更小的配置文件和更少的混乱,因为该语言是专门为解决特定领域问题而设计的。按照惯例,Gradle的配置文件在Groovy中称为build.gradle,在Kotlin中称为build.gradle.kts。

请注意,Kotlin在自动完成和错误检测方面提供了比Groovy更好的IDE支持。

下面是一个build.gradle文件的示例,该文件用于与之前的HelloWorld主类相同的简单Java项目:

apply plugin: 'java'

repositories {
    mavenCentral()
}

jar {
    baseName = 'gradleExample'
    version = '1.0.0'
}

dependencies {
    testImplementation 'junit:junit:4.12'
}

我们可以通过运行以下命令来编译代码:

gradle classes

Gradle的核心是有意提供非常少的功能,插件添加了所有有用的功能。在我们的示例中,我们使用了java插件,它允许我们编译Java代码和其他有价值的功能。

Gradle将其构建步骤命名为“任务”,而不是Ant的“目标”或Maven的“阶段”。在Maven中,我们使用了Apache Maven Dependency插件,它的一个特定目标是将依赖项复制到指定目录。使用Gradle,我们可以通过使用任务来做同样的事情:

task copyDependencies(type: Copy) {
    from configurations.compile
    into 'dependencies'
}

我们可以通过执行以下命令来运行此任务:

gradle copyDependencies

5. 总结

在本文中,我们介绍了Ant、Maven和Gradle-三种Java构建自动化工具。

毫不奇怪,Maven占据了当今构建工具市场的大部分。

然而,Gradle在更复杂的代码库中得到了很好的采用,原因如下:

  • 许多开源项目,如Spring,现在都在使用它
  • 在大多数情况下,它比Maven更快,这要归功于它的增量构建
  • 它提供高级分析和调试服务

然而,Gradle似乎有一个更陡峭的学习曲线,特别是如果你不熟悉Groovy或Kotlin。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章