Java构建工具:Maven与Gradle的对比

在Java码农的世界里,构建工具一直是一个不可或缺的元素。一开始,世上是只有一个构建工具的那就是Make后来发展为GNU Make。但是由于需求的不断涌现,这个小圈子里又逐渐衍生出其他千奇百怪的构建工具。

在这个小圈子中影响力最大的角色莫过于Maven了。它使用XML作为配置文件,改进了前辈Ant的复杂的构建配置,提供了一些现成的目标,而不需要我们一个个的将构建任务的每个命令一一列出。另外它提供了一个杀手锏功能,那就是依赖管理,它通过简单的配置就可以自动从网络上下载项目所需的依赖,这革命性的改变了我们开发软件的方式。可以想象,如果你是一个大型软件开发项目组的成员,如果使用代码仓库管理依赖jar包会令仓库变得多么庞大!Maven的制品仓库设计实现了制品与代码间的解耦,为基于制品的协作提供了可能。

可是软件行业新旧交替的速度之快往往令人咋舌,不用多少时间,你就会发现曾经大红大紫的技术已经成了昨日黄花。在Java构建领域,我们能够看到一些新兴的工具在涌现。比如基于Groovy的Gradle。Hibernate就将自己的项目从Maven迁移到了Gradle,Google官方Android开发的IDE Android Studio也默认使用了Gradle进行构建。这些事件令Gradle吸引了不少眼球。Gradle真的要替代Maven了么?当然没有,Maven在如今仍然是Java构建技术的事实标准。Gradle也仍然使用了Maven的制品库来做依赖管理。但是从Gradle身上,我们确实看到了进步。简洁的Groovy语法和灵活的配置令我们眼前一亮。

那Maven和Gradle到底有何不同呢?就请读者和我一起探寻吧。

安装
在安装上两者大同小易。我们都需要从官网下载解压到本地目录。配置好MAVEN_HOME或Gradle_Home环境变量,并加入PATH环境变量中。我们就可以在命令行中使用maven和gradle了。

主流的Java IDE: Eclipse可以安装Maven和Gradle的插件。Intellij有内置的Gradle和Maven可以使用。

二者均有详尽的文档供用户参考。别看gradle是个新来的小子,它的文档也是有70章,500多页的内容的!

在这里附上Maven和Gradle的下载地址:

maven: Maven – Welcome to Apache Maven
gradle: https://gradle.org
依赖管理
Maven的配置文件是.pom文件。POM是项目对象模型(Project Object Model)的简称,它是Maven项目中的文件,使用XML表示。其中包含项目的基本信息,构建过程,环境信息,依赖信息等。我们可以看下面这个简单的例子:

<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.0modelVersion>
    <groupId>com.vsgroupId>
    <artifactId>com.vs.maven.gradleartifactId>
    <version>1.0version>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>1.2.6.RELEASEversion>
    parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-jpa
            artifactId>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.25version>
        dependency>
    dependencies>

    <properties>
        <java.version>1.8java.version>
    properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
project>

这个例子构建了一个简单的spring-boot项目, 最开始定义了一些项目的基本信息,包括组名、制品名、版本等。parent标签表示我们继承了一个spring定义的一个制品的配置,这样我们不需要配置很多依赖的版本就可以引入依赖。dependencies标签间配置该项目所依赖的其他制品,分别配置每个依赖制品的groupId, artifactId和version。当我们执行mvn insall时,maven就会自动下载依赖,并帮我们将它编译打包放入本地仓库之中。我们就可以在用户目录下的.m2文件夹中找到我们的制品。

那如果我们使用Gradle来构建这个项目,我们该如何做呢?

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.6.RELEASE")
    }
}
dependencies {
    compile("org.springframework.boot:spring-boot-starter-web") {
        exclude module: "spring-boot-starter-tomcat"
    }
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    testCompile("mysql:mysql-connector-java:5.1.25")
}

咦?冗长的代码怎么突然少了这么多?^?

仔细阅读下你会发现,原来是依赖管理所需的配置长度变短了。在pom.xml中我们需要引入一个依赖时需要将它的groupId, artifactId和version都用标签引起来。但是在build.gradle中你会发现,仅仅需要将三者的value用:连起来,并"调用compile函数"就可以啦。

比如,我们要引用spring-boot的starter-security,maven的配置是这样写的:

<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-securityartifactId>
    dependency>
dependencies>

在gradle中的配置却是这样的:

dependencies {
    compile("org.springframework.boot:spring-boot-starter-security")
}

觉得怎么样?我反正感觉和写代码一样清爽!Gradle使用了groovy作为它的DSL,非常的易用。如果你使用了很久的Maven,你也许会发现Gradle的配置写起来实在是太爽了!

构建生命周期管理
除了依赖管理以外,构建工具的另一个主要用途就是构建的生命周期管理。

Maven有三个生命周期,每个生命周期又分为多个阶段:

Clean:包含3个阶段,与清理上次构建生成的文件相关
Default:Maven的核心生命周期,包含多个阶段如预处理、编译、测试、打包、安装到本地仓库、发布到远程仓库等。
Site: 包含4个阶段,与生成项目报告,站点,发布站点相关。
这些生命周期都是系统自定义好的,如果我们需要修改现有的构建生命周期的话,我们就要编写一个Maven插件。因为Maven是通过插件发来完成大多数的构建任务。每个插件可以绑定一个生命周期。配置好绑定生命周期后,我们需要定义插件的任务,在Maven中每个任务的goal称作Mojo,每个Mojo我们都需要实现org.apache.maven.plugin.Mojo接口。也就是我们需要定义一个类来实现这个接口。使用时我们需要引入这个插件,并配置需要执行的goal。

比如我们要完成输出Hello world这个需求的话,我们需要:

新建GreeingMojo类:

package sample.plugin;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;

/**
 * Says "Hi" to the user.
 *
 */
@Mojo( name = "sayhi")
public class GreetingMojo extends AbstractMojo
{
    public void execute() throws MojoExecutionException
    {
        getLog().info( "Hello, world." );
    }
}

定义pom文件:

<project>
  <modelVersion>4.0.0modelVersion>

  <groupId>sample.plugingroupId>
  <artifactId>hello-maven-pluginartifactId>
  <version>1.0-SNAPSHOTversion>
  <packaging>maven-pluginpackaging>

  <name>Sample Parameter-less Maven Pluginname>

  <dependencies>
    <dependency>
      <groupId>org.apache.mavengroupId>
      <artifactId>maven-plugin-apiartifactId>
      <version>2.0version>
    dependency>

    
    <dependency>
      <groupId>org.apache.maven.plugin-toolsgroupId>
      <artifactId>maven-plugin-annotationsartifactId>
      <version>3.4version>
      <scope>providedscope>
    dependency>
  dependencies>
project>

在项目pom文件目录运行install命令将插件安装到本地仓库
在使用插件的项目加入配置:

 <build>
    <plugins>
      <plugin>
        <groupId>sample.plugingroupId>
        <artifactId>hello-maven-pluginartifactId>
        <version>1.0-SNAPSHOTversion>
      plugin>
    plugins>
  build>

执行:

mvn groupId:artifactId:version:goal

即可完成Hello,world的输出。

那么在Gradle中我们该怎么做呢?Gradle中有一个基本概念叫Task,我们可以使用Task来完成这个需求:

task hello << {
    println "hello world"
}

执行Gradle hello,即可完成Hello, World的输出。是不是很简单?像写代码一样~

当然实际工程我们要完成的构建任务不仅仅是输出一个info这么简单,我们很可能会去做一些其他复杂的操作,比如初始化文件、数据库,检测系统环境等等。但由于Gradle使用了Groovy作为配置文件,在使用时会比Maven的xml配置灵活许多,更适合我们码农进行使用。

制品发布
在制品发布这个操作上,Maven要扳回一局。Maven原生支持maven jar的格式,发布很简单;而Gradle虽说既支持Maven又支持Gradle,但是就要我们自己做很多额外的工作。比如Maven要发布制品,只需要配置远程仓库的参数:

  <distributionManagement>
    <repository>
      <id>internalid>
      <name>Internal Release Repositoryname>
      <url>http://repository.springsource.com/maven/bundles/releaseurl>
    repository>
  distributionManagement>

而gradle发布制品,还需要生成pom文件:

uploadArchives {
    repositories {
        mavenDeployer {
            //为Pom文件做数字签名
            beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

            repository(url: "http://repository.springsource.com/maven/bundles/release") {
                authentication(userName: username, password: password)
            }
            //构造项目的Pom文件
            pom.project {
                name project.name
                packaging 'jar'
                description 'description'

            }
        }
    }
}

总结
因为时间关系,简单介绍了这么多,可能读者也对Gradle与Maven的差别有了一些了解。Gradle与Maven相比更为灵活,简单。但是Maven相比于Gradle的不灵活,是否也是它的优点呢?这就需要读者在工程中自己进行思考了。

除此之外Gradle的官方网站专门给出了一个专栏来讲Gradle与Maven的区别: Maven vs Gradle: Feature Comparison。

有耐心的读者可以看看这些对比。如果说你要说我没耐心看完这些,只想快点挑个构建工作开始我的项目! 那么我要说的是:Just have a try! Maven和Gradle都是非常优秀的构建工具,增加二者的使用经验不是一个很亏的事情。当然如果你要开发Android应用的话,还是推荐你使用Gradle做构建工具,因为Google官方推的Android Studio就使用了Gradle作为原生构建工具,这使得Gradle对Android各版本软件的构建支持得更好一些。其他项目的话,二者选其一吧~

你可能感兴趣的:(java,maven,开发语言)