Gradle的双刃

作为java开发者,maven解决了我很多头痛的问题,现在也几乎成了java项目中依赖管理和构建的标准工具,很多开源的库都会发布到maven中央仓库。以为的经验来说,maven完全够用了,在大型多模块微服务系统中使用一样没问题。这主要得益于maven优秀的约定,生命周期,和强大而众多的插件。唯一比较烦maven的一点就是配置多,我曾经在一个parent pom中有一千多行配置,另外一点就是maven的传递依赖也是把双刃剑,容易出现最总编译出来的包中所依赖的jar包版本错误。

其实如果能接受上面maven的问题,那也暂时没有使用gradle的必要。那gradle是什么呢,凭什么替代maven,凭什么迁移过去?gradle在安卓开发中使用广泛,我并不清楚安卓,所以仅从java角度看gradle。简单来说,gradle是基于groovy,所以配置文件可以按照groovy的语法自由编写,就因此,它相对maven来说,配置简单,使用灵活。简单在于不再像maven的xml那么繁杂,灵活在于可以自由定义各种运行任务,而不像maven定死了生命周期的每一个阶段,插件也只能绑定到对应阶段执行。

其实gradle就是一个脚本,这个脚本可以开发出各种各样的task,再依赖一些插件,即可完成包依赖和项目构建。而gradle能获得很多用户的另一个原因是,它可以完全使用maven的包和仓库,你不用担心去哪儿下载的问题也不用担心公司maven私服的迁移。并且,它的项目结构也可以跟maven完全一样,唯一的不同就是pom.xml变成了build.gradle

gradle的好处已经说了:简洁、灵活。简洁很好,但灵活并不一定是好事儿,如果hold不住,可能在项目开发前被配置搞得精疲力尽,或者中途瞎改,搞乱了。这方面仁者见仁智者见智,个人感觉是出问题没有maven好定位,毕竟maven定死了那些规则和配置,跑不偏。只是对于大部分开发者来说,能自由地组合,不死板,想干什么就干什么是一件比较不错的事儿。

下面简单介绍使用gradle。

安装

wget https://downloads.gradle.org/distributions/gradle-4.0.1-bin.zip
unzip gradle-4.0.1-bin.zip

根据安装目录添加环境变量到文件如/etc/profile或者mac ~/.bash_profile

export GRADLE_HOME=/usr/local/gradle-4.0.1
export PATH=$PATH:$GRADLE_HOME/bin
gradle -v
------------------------------------------------------------
Gradle 4.0.1
------------------------------------------------------------

Build time:   2017-07-07 14:02:41 UTC
Revision:     38e5dc0f772daecca1d2681885d3d85414eb6826

Groovy:       2.4.11
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_91 (Oracle Corporation 25.91-b14)
OS:           Mac OS X 10.11.6 x86_64

安装成功

Spring boot项目

plugins {
    id 'org.springframework.boot' version '1.5.2.RELEASE'
    id 'java'
    id 'maven'
}

repositories {
    jcenter()
    mavenLocal()
    mavenCentral()
    maven {
        url "http://maven.aliyun.com/nexus/content/groups/public/"
    }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile "com.github.tomakehurst:wiremock:2.6.0"
    compile 'com.squareup.okhttp3:okhttp:3.8.1'
    integTestCompile 'org.codehaus.groovy:groovy-all:2.4.3'
    integTestCompile 'org.spockframework:spock-core:0.7-groovy-2.0', {
        exclude module: 'groovy-all'
    }
}

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "http://localhost:8088/nexus/content/repositories/snapshots/") {
                authentication(userName: "admin", password: "admin123")
                pom.groupId = "com.thoreau"
                pom.artifactId = "spring-boot"
            }
        }
    }
}
sourceSets {
    main {
        java {
            srcDir 'src/main/java'
        }
        resources {
            srcDir 'src/main/resources'
        }
    }
}

介绍:
* plugins: 配置插件,比如这儿用到的spring boot插件,提供了bootRuntask。
* repositories:配置包的仓库,示例中配置了maven本地和中央仓库,还有阿里的私服。
* dependencies:配置依赖
* uploadArchives:配置maven上传(dploy)
* sourceSets:如上,项目结构设置

这相当于把maven项目迁移过来。

Task

ext {
    springVersion = "3.1.0.RELEASE"
    emailNotification = "build@master.org"
}
task compile {
    doLast {
        println 'compiling source'
    }
}

task compileTest(dependsOn: compile) {
    doLast {
        println 'compiling unit tests'
    }
}

task test(dependsOn: [compile, compileTest]) {
    doLast {
        println 'running unit tests'
    }
}

task dist(dependsOn: [compile, test]) {
    doLast {
        println 'building the distribution'
    }
}
task printProperties {
    doLast {
        println springVersion
        println emailNotification
    }
}

执行gradle dist -q

compiling source
compiling unit tests
running unit tests
building the distribution

执行gradle printProperties -q

3.1.0.RELEASE
build@master.org

这只是简单的示例,Gradle里面的所有东西都基于两个概念:project和task。roject通常指一个项目,而task指构建过程中的任务。在task中可以任意使用变量或者分支循环,还能使用第三方包(需要在buildScript依赖)。

从示例中也能体会到,确实简洁灵活,给人的整体感觉是比maven‘现代’很多。对个人来说,我很乐意转到gradle。


参考:
* https://spring.io/guides/gs/gradle/
* https://docs.gradle.org/current/userguide/userguide.html
* https://tech.meituan.com/gradle-practice.html

CONTENTS