Gradle 基础知识与原理(1)-- ant, maven, gradle

本文主要介绍 Gradle 的一些基础知识与原理。

本文主要包括以下内容:

Gradle 的前世今生
前世
1. 构建工具的进化:Ant, Maven, Gradle
今生
1. Gradle 到底是什么?
2. Gradle Wrapper 是什么?
3. AGP 到底是什么?
4. gradle.properties 是什么?
5. settings.gradle 是什么?
6. build.gradle 是什么?
7. Gradle 生命周期是怎样的?
8. build.gradle 配置详解。

首先来回答一个问题吧:什么是 Gradle 呢?我理解的话,就是一 “构建(build)” 项目的工具,常见的使用场景的呢,就是咱们编写的 Java 代码、C++ 代码和资源文件经过编译、链接等操作,最终打包成一个 apk
下面咱们先来了解一下,什么是构建工具,它又是怎么衍化的。

一、构建工具的进化:ant, maven, gradle

我们要写一个 Java 程序,一般的步骤也就是编译,测试,打包。这个构建的过程,如果文件比较少,我们可以手动使用 java, javac, jar 命令去做这些事情。但当工程越来越大,文件越来越多,这个事情就不是那么地令人开心了。因为这些命令往往都是很机械的操作。但是我们可以把机械的东西交给机器去做。
这时,构建工具就应运而生了。

1. Apache Ant

linux 上,有一个工具叫 make。我们可以通过编写 Makefile 来执行工程的构建。windows 上相应的工具是 nmake。这个工具写起来比较罗嗦,所以从早期,Java 的构建就没有选择它,而是 Apach 基金组织新建的一个叫做 Ant 的构建项目工具。Ant 的思想和 makefile 比较像。定义一个任务,规定它的依赖,然后就可以通过 Ant 来执行这个任务了。我们通过例子看一下。下面列出一个 Ant 工具所使用的 build.xml

<?xml version="1.0" encoding="UTF-8" ?>  
<project name="HelloWorld" default="run" basedir=".">  
<property name="src" value="src"/>  
<property name="dest" value="classes"/>  
<property name="jarfile" value="hello.jar"/>  
<target name="init">  
   <mkdir dir="${dest}"/>  
</target>  
<target name="compile" depends="init">  
   <javac srcdir="${src}" destdir="${dest}"/>  
</target>  
<target name="build" depends="compile">  
   <jar jarfile="${jarfile}" basedir="${dest}"/>  
</target>  
<target name="test" depends="build">  
   <java classname="test.ant.HelloWorld" classpath="${hello_jar}"/>  
</target>  
<target name="clean">  
   <delete dir="${dest}" />  
   <delete file="${hello_jar}" />  
</target>  
</project>  

可以看到 Ant 的构建脚本还是比较清楚的。Ant 定义了五个任务:init, compile, build, test, clean,每个任务做什么都定义清楚了。打包之前要先编译,所以通过 depends 来指定依赖的路径。如果在命令行里执行 ant build,那就会先执行compile,而 compile 又依赖于 init,所以就会先执行 init。看起来很合理,对吧?有了这个东西以后,我们只要一条命令:

ant test

就可以执行编程,打包,测试了。为开发者带来了很大的便利。
其实在 Android Studio 出来之前,我们在 eclipse 中也有构建项目的概念,当时用的就是 Antgoogle 给我们集成到 SDK 中了,我们当初之所以能把一大堆 Java 代码和图片打包成一个 apk 主要靠它。
但是 Ant 有一个很致命的缺陷,那就是没办法管理依赖。我们一个工程,要使用很多第三方工具,不同的工具,不同的版本。每次打包都要自己手动去把正确的版本拷到 lib 下面去,不用说,这个工作既枯燥还特别容易出错。为了解决这个问题,我们来看 Maven 如何完成同样的工作。

2. Apache Maven

Maven 最核心的改进就在于提出仓库这个概念,它抛弃了 Ant 中通过 target 定义任务的做法。我们可以把所有依赖的包,都放到仓库里去,在我们的工程管理文件里,标明我们需要什么什么包,什么什么版本。在构建的时候,Maven 就自动帮我们把这些包打到我的包里来了。我们再也不用操心着自己去管理几十上百个 jar 文件了。

Maven 提出,要给每个包都标上坐标,这样,便于在仓库里进行查找。所以,使用 Maven 构建和发布的包都会按照这个约定定义自己的坐标。例如:

pom.xml

[html] view
plaincopy
<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>  

上面,定义了用到包的坐标是 junit:junit:4.11,而我的工程要依赖 junit:junit:4.10。那么 maven 就会自动去帮我把 junit 打包进来。如果我本地没有 junitmaven 还会帮我去网上下载。下载的地方就是远程仓库,我们可以通过 repository 标签来指定远程仓库。
通过执行下面的命令来运行 maven goal 生成 jar 文件。

mvn package  

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

pom.xml

[plain] view
plaincopy
<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 

我们需要写很多 xml 来进行基本的常用的任务。在实际项目中有更多的依赖和 taskMavenpom.xml 很容易就有成百上千行的配置。

既然有缺点,那肯定也有优点,Maven 的主要优点是引入了生命周期的概念。这个问题我们暂时先放一下。

Maven 已经很好了,可以满足绝大多数工程的构建。那为什么我们还需要新的构建工具呢?依赖管理不能很好地处理相同库文件不同版本之间的冲突;xml 作为配置文件的格式有严格的结构层次和标准,定制化目标很困难;因为 Maven 主要聚焦于依赖管理,实际上用 Maven 很难写出复杂、定制化的构建脚本,甚至不如 Ant ;用xml 写的配置文件会变得越来越大,越来越笨重。在大型项目中,它经常什么“特别的”事还没干就有几百行代码。基于这些原因,我们来看今天的主要内容 Gradle

3. Gradle Build Tool

随着时间的推移,开发人员对拥有和使用 DSL(Domain Specific Languages ) 越来越感兴趣——简单地说,这将允许他们使用为特定领域定制的语言来解决特定领域中的问题。

Gradle 采用了这种方法,它使用的是基于 GroovyKotlinDSL。这导致了更小的配置文件和更少的混乱,因为该语言是专门为解决特定领域的问题而设计的。按照惯例,Gradle 的配置文件在 Groovy 中称为 build.Gradle,在Kotlin 中称为 build.Gradle.kts 。注意,Kotlin 在自动完成和错误检测方面提供了比 Groovy 更好的IDE支持。

而且,Gradle 并不是另起炉灶,它基于 Groovy 语言,并充分地使用了 Maven 的现有资源。继承了 Maven 中仓库,坐标,依赖这些核心概念。文件的布局也和 Maven 相同。但同时,它又继承了 Anttarget 的概念,我们又可以重新定义自己的任务了(gradle 中叫做 task)。

简单点,Gradle 是一个依赖管理和构建自动化工具。

我们来体验一下,新建一个空目录,在命令行,执行

gradle init --type java-library

可以看到新创建了一个工程,工程根目录下,主要看这几项:

build.gradle  gradle  settings.gradle  src

我们看一下,build.gradle 的内容:

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java Library project to get you started.
 * For more details take a look at the Java Libraries chapter in the Gradle
 * User Manual available at https://docs.gradle.org/6.5/userguide/java_library_plugin.html
 */

plugins {
    // Apply the java-library plugin to add support for Java Library
    id 'java-library'
}

repositories {
    // Use jcenter for resolving dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
}

dependencies {
    // This dependency is exported to consumers, that is to say found on their compile classpath.
    api 'org.apache.commons:commons-math3:3.6.1'

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation 'com.google.guava:guava:29.0-jre'

    // Use JUnit test framework
    testImplementation 'junit:junit:4.13'
}

内容很简单,引入了 java 插件,指定仓库,指定依赖。可以看到依赖的设定相比起 xml 的写法,变得大大简化了。

使用 Gradle,任务又变成了核心概念了。我们就来体验一下任务。

build.gradle 里添加这样的任务:

task hello  { 
    println 'welcome to gradle';
}

然后在命令行执行

gradle -q hello
注:-q 参数。用来控制 Gradle 的日志级别,可以保证只输出我们需要的内容。

就可以看见打印一行 "welcome to gradle"。在使用 maven 构建的时候,如果想临时对某一个构建任务加一点 log,会是个非常困难的事情 。但在 Gradle 里,就变得非常简单,因为 gradle 的背后其实是 groovy 这个编程语言在起作用。为了验证这一点,我们再改一下:

task hello {
    3.times {
        println 'welcome to gradle';
    }   
}

然后执行 gradle -q hello,就可以看到连续打印了三行。使用脚本语言进行构建,这几乎给了我们任何的能力,我们可以在构建的时候做任何的事情,甚至你可以直接让 Gradle 帮你做表达式求值。

接下来,我们来认识一下 Gradle

二.、Gradle 基础知识与原理

Gradle 基础知识与原理2

最后,参考链接:

Ant 、Maven和Gradle的比较
构建工具的进化:ant, maven, gradle

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容