蚂蚁和Maven之间的区别 [已关闭]

2022-08-31 06:38:39

有人能告诉我蚂蚁和Maven之间的区别吗?我也从未使用过。我知道它们用于自动化Java项目的构建,但我不知道从哪里开始。


答案 1

《Maven: The Definitive Guide》一书中,我在引言中写了Maven和Ant之间的差异,章节标题是“Ant和Maven之间的差异”。这是一个答案,是该介绍中的信息与一些附加说明的组合。

简单比较

我向您展示这一点只是为了说明在最基本的层面上,Maven具有内置约定的想法。下面是一个简单的 Ant 构建文件:

<project name="my-project" default="dist" basedir=".">
    <description>
        simple example build file
    </description>   
    <!-- set global properties for this build -->   
    <property name="src" location="src/main/java"/>
    <property name="build" location="target/classes"/>
    <property name="dist"  location="target"/>

    <target name="init">
      <!-- Create the time stamp -->
      <tstamp/>
      <!-- Create the build directory structure used by compile -->
      <mkdir dir="${build}"/>   
    </target>

    <target name="compile" depends="init"
        description="compile the source " >
      <!-- Compile the java code from ${src} into ${build} -->
      <javac srcdir="${src}" destdir="${build}"/>  
    </target>

    <target name="dist" depends="compile"
        description="generate the distribution" >
      <!-- Create the distribution directory -->
      <mkdir dir="${dist}/lib"/>

      <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file
-->
      <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
   </target>

   <target name="clean"
        description="clean up" >
     <!-- Delete the ${build} and ${dist} directory trees -->
     <delete dir="${build}"/>
     <delete dir="${dist}"/>
   </target>
 </project>

在这个简单的 Ant 示例中,您可以看到如何确切地告诉 Ant 该做什么。有一个编译目标,其中包括javac任务,该任务将src/main/java目录中的源代码编译为target/classes目录。你必须告诉 Ant 你的源代码在哪里,你希望将生成的字节码存储在哪里,以及如何将所有这些打包到一个 JAR 文件中。虽然最近的一些发展有助于降低 Ant 的过程性,但开发人员使用 Ant 的经验是编写用 XML 编写的过程语言。

将前面的 Ant 示例与 Maven 示例进行对比。在 Maven 中,要从某个 Java 源代码创建 JAR 文件,您需要做的就是创建一个简单的 pom.xml,将源代码放在 ${basedir}/src/main/java 中,然后从命令行运行 mvn install。示例 Maven pom.xml,可获得相同的结果。

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.sonatype.mavenbook</groupId>
  <artifactId>my-project</artifactId>
  <version>1.0</version>
</project>

这就是你所需要的一切.xml。从命令行运行 mvn install 将处理资源、编译源代码、执行单元测试、创建 JAR,并将 JAR 安装在本地存储库中以便在其他项目中重用。无需修改,您就可以运行 mvn 站点,然后在目标/站点中找到一个索引.html文件,其中包含指向 JavaDoc 的链接以及一些关于源代码的报告。

诚然,这是最简单的示例项目。仅包含源代码并生成 JAR 的项目。遵循 Maven 约定且不需要任何依赖项或自定义的项目。如果我们想开始自定义行为,我们的pom.xml将会越来越大,在最大的项目中,你可以看到非常复杂的Maven POM的集合,其中包含大量的插件自定义和依赖声明。但是,即使您的项目的POM文件变得更加重要,它们也包含与使用Ant的类似大小的项目的构建文件完全不同的信息。Maven POMs包含声明:“这是一个JAR项目”和“源代码在src / main / java中”。Ant 构建文件包含明确的说明:“这是项目”,“源代码在”,“针对此目录运行”,“将结果放入”,“从....”创建JAR等。Ant必须明确说明这个过程,Maven有一些“内置”的东西,只需要知道源代码在哪里以及应该如何处理它。src/main/javajavactarget/classses

高级比较

在这个例子中,蚂蚁和Maven之间的区别是什么?蚂蚁。。。

  • 没有像通用项目目录结构那样的正式约定,你必须告诉 Ant 在哪里可以找到源代码,在哪里可以找到输出。随着时间的推移,非正式惯例已经出现,但它们尚未被编入产品中。
  • 是程序性的,你必须告诉蚂蚁到底该做什么以及什么时候该做。你必须告诉它编译,然后复制,然后压缩。
  • 没有生命周期,您必须定义目标和目标依赖关系。您必须手动将一系列任务附加到每个目标。

其中 Maven...

  • 有约定,它已经知道你的源代码在哪里,因为你遵循了约定。它将字节码放在目标/类中,并在目标中生成一个JAR文件。
  • 是声明性的。您所要做的就是创建一个pom.xml文件,并将源代码放在默认目录中。Maven负责其余的工作。
  • 具有生命周期,您在执行 时调用了该生命周期。此命令告诉 Maven 执行一系列序列步骤,直到到达生命周期。作为整个生命周期中这段旅程的副作用,Maven执行了许多默认插件目标,这些目标可以执行编译和创建JAR之类的操作。mvn install

常春藤呢?

是的,所以像史蒂夫·洛夫兰这样的人会读到这个比较并称之为犯规。他将讨论答案如何完全忽略了一种叫做Ivy的东西,以及Ant可以在最近的Ant版本中重用构建逻辑的事实。这是事实。如果你有一群聪明的人使用蚂蚁+蚂蚁+常春藤,你最终会得到一个设计精良的构建。尽管我非常相信Maven是有道理的,但我很乐意与一个拥有非常敏锐的构建工程师的项目团队一起使用Ant + Ivy。话虽如此,我确实认为你最终会错过许多有价值的插件,比如Jetty插件,你最终会做一大堆你不需要做的工作。

比Maven vs. Ant更重要

  1. 是使用存储库管理器来跟踪软件工件。我建议下载Nexus。您可以使用 Nexus 代理远程存储库,并为团队提供部署内部工件的位置。
  2. 您有适当的软件组件模块化。一个大的单片组件很少会随着时间的推移而扩展。随着项目的发展,您将需要具有模块和子模块的概念。Maven非常适合这种方法。
  3. 您为构建采用一些约定。即使您使用 Ant,您也应该努力采用某种与其他项目一致的约定。当一个项目使用Maven时,这意味着任何熟悉Maven的人都可以拿起构建并开始运行它,而不必为了弄清楚如何编译它而摆弄配置。

答案 2

Maven 是一个框架,Ant 是一个工具箱

Maven是一辆预先建造的公路车,而Ant是一套汽车零件。使用Ant,您必须制造自己的汽车,但至少如果您需要进行任何越野驾驶,则可以制造出正确类型的汽车。

换句话说,Maven是一个框架,而Ant是一个工具箱。如果你满足于在框架的范围内工作,那么Maven会做得很好。对我来说,问题是我一直撞到框架的边界,它不会让我出去。

XML 详细程度

tobrien是一个对Maven了解很多的人,我认为他对这两种产品进行了非常好,诚实的比较。他将一个简单的 Maven pom.xml与一个简单的 Ant 构建文件进行了比较,并提到了 Maven 项目如何变得更加复杂。我认为值得一看的是,在一个简单的现实世界项目中,您更有可能看到几个文件的比较。下面的文件表示多模块版本中的单个模块。

首先,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-4_0_0.xsd">

    <parent>
        <groupId>com.mycompany</groupId>
        <artifactId>app-parent</artifactId>
        <version>1.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>persist</artifactId>
    <name>Persistence Layer</name>

    <dependencies>

        <dependency>
            <groupId>com.mycompany</groupId>
            <artifactId>common</artifactId>
            <scope>compile</scope>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>com.mycompany</groupId>
            <artifactId>domain</artifactId>
            <scope>provided</scope>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate</artifactId>
            <version>${hibernate.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>${commons-lang.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
            <version>${spring.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.dbunit</groupId>
            <artifactId>dbunit</artifactId>
            <version>2.2.3</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng.version}</version>
            <scope>test</scope>
            <classifier>jdk15</classifier>
        </dependency>

        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>${commons-dbcp.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc</artifactId>
            <version>${oracle-jdbc.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.easymock</groupId>
            <artifactId>easymock</artifactId>
            <version>${easymock.version}</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

和等效的 Ant 文件:

<project name="persist" >

    <import file="../build/common-build.xml" />


    <path id="compile.classpath.main">
        <pathelement location="${common.jar}" />
        <pathelement location="${domain.jar}" />
        <pathelement location="${hibernate.jar}" />
        <pathelement location="${commons-lang.jar}" />
        <pathelement location="${spring.jar}" />
    </path>


    <path id="compile.classpath.test">
        <pathelement location="${classes.dir.main}" />
        <pathelement location="${testng.jar}" />
        <pathelement location="${dbunit.jar}" />
        <pathelement location="${easymock.jar}" />
        <pathelement location="${commons-dbcp.jar}" />
        <pathelement location="${oracle-jdbc.jar}" />
        <path refid="compile.classpath.main" />
    </path>


    <path id="runtime.classpath.test">
        <pathelement location="${classes.dir.test}" />
        <path refid="compile.classpath.test" />
    </path>


</project>

tobrien用他的例子来表明Maven有内置的约定,但这并不一定意味着你最终会写更少的XML。我发现事实恰恰相反。pom.xml比构建长3倍.xml这并没有偏离惯例。实际上,我的 Maven 示例没有显示配置插件所需的额外 54 行。那个pom.xml是一个简单的项目。当您开始添加额外的需求时,XML 确实开始显着增长,这对于许多项目来说并不罕见。

但你必须告诉蚂蚁该做什么

当然,我上面的蚂蚁例子并不完整。我们仍然需要定义用于清理,编译,测试等的目标。这些在由多模块项目中的所有模块导入的通用生成文件中定义。这让我想到了一点,所有这些东西都必须在Ant中明确地编写,而在Maven中它是声明性的。

没错,如果我不必明确地编写这些Ant目标,它将节省我的时间。但是需要多少时间呢?我现在使用的常见构建文件是我5年前编写的,从那时起只有轻微的改进。在我对Maven进行了2年的实验之后,我从壁橱里拿出旧的蚂蚁构建文件,把它掸去灰尘,然后让它重新开始工作。对我来说,在5年的时间里,必须明确告诉蚂蚁该做什么的成本加起来不到一周。

复杂性

我想提到的下一个主要区别是复杂性及其在现实世界中的影响。Maven的构建旨在减少负责创建和管理构建过程的开发人员的工作量。为了做到这一点,它必须很复杂。不幸的是,这种复杂性往往会否定他们的预期目标。

与蚂蚁相比,Maven项目的构建人员将花费更多的时间:

  • 阅读文档:关于Maven的文档更多,因为您需要学习的内容还有很多。
  • 教育团队成员:他们发现询问知道的人比试图自己找到答案更容易。
  • 对构建进行故障排除:Maven不如Ant可靠,尤其是非核心插件。此外,Maven 构建是不可重复的。如果您依赖于插件的 SNAPSHOT 版本(这很有可能),则您的构建可能会在您未更改任何内容的情况下中断。
  • 编写 Maven 插件:插件通常在编写时会考虑特定的任务,例如创建一个 webstart 捆绑包,这使得将它们重用于其他任务或将它们组合在一起以实现目标变得更加困难。因此,您可能需要编写自己的一个来解决现有插件集中的差距。

相比之下:

  • Ant 文档简洁、全面且全部集中在一个地方。
  • 蚂蚁很简单。一个试图学习 Ant 的新开发人员只需要了解几个简单的概念(目标、任务、依赖关系、属性),就能弄清楚他们需要知道的其余内容。
  • 蚂蚁是可靠的。在过去的几年里,蚂蚁的发布并不多,因为它已经奏效了。
  • Ant构建是可重复的,因为它们通常是在没有任何外部依赖关系的情况下创建的,例如在线存储库,实验性第三方插件等。
  • 蚂蚁是全面的。因为它是一个工具箱,所以您可以组合这些工具来执行几乎任何您想要的任务。如果您需要编写自己的自定义任务,则非常简单。

熟悉

另一个区别是熟悉度。新开发人员总是需要时间来跟上速度。在这方面,熟悉现有产品会有所帮助,Maven的支持者正确地声称这是Maven的一个好处。当然,Ant 的灵活性意味着您可以创建任何您喜欢的约定。所以我使用的约定是将源文件放在目录名称src/main/java中。我编译的类进入一个名为 target/classes 的目录。听起来很熟悉,不是吗。

我喜欢Maven使用的目录结构。我认为这是有道理的。还有它们的构建生命周期。因此,我在 Ant 构建中使用相同的约定。不仅仅是因为它有意义,而且因为以前使用过Maven的人都会熟悉它。


推荐