Java世界中主要有三大构建工具:Ant、Maven和Gradle。经过几年的发展,Ant几乎销声匿迹、Maven也日薄西山,而Gradle的发展则如日中天。
ANT是最早的构建工具,其主要基于IDEA,在2000年的时候最流行java构建工具,虽然对工程构建过程中的过程控制特别好,也比较灵活,但是它的XML脚本编写格式让XML文件特别大。
Maven主要是用来填补Ant的坑的,Maven第一次支持了从网络上下载的功能,仍然采用xml作为配置文件格式,其主要专注的是依赖管理,主要好处是它的生命周期。虽然接连的多个项目生命周期相同,这是以灵活性为代价的。 Maven也面临着依赖管理的一些问题。它不会在同一库版本之间处理好矛盾,复杂的定制构建脚本实际上Maven比ANT更难写。
Grale是一个自动化的构建工具,Gradle属于结合以上两个的优点,它继承了Ant的灵活和Maven的生命周期管理,它最后被google作为了Android御用管理工具。它最大的区别是不用XML作为配置文件格式,采用了DSL格式,使得脚本更加简洁。Gradle引入了基于Groovy语言的DSL语法来代替XML配置,因此它的配置文件是一个Groovy文件。
Gradle 的核心在于基于 Groovy 的丰富而可扩展的域描述语言(DSL)。 Groovy 通过声明性的语言元素将基于声明的构建推向下层,你可以按你想要的方式进行组合。 这些元素同样也为支持 Java, Groovy,OSGi,Web 和 Scala 项目提供了基于约定的构建。 并且,这种声明性的语言是可以扩展的。你可以添加新的或增强现有的语言元素。 因此,它提供了简明、可维护和易理解的构建。
声明性语言优点在于通用任务图,你可以将其充分利用在构建中. 它提供了最大限度的灵活性,以让 Gradle 适应你的特殊需求。
Gradle 的灵活和丰富性最终能够支持在你的构建中应用通用的设计模式。 例如,它可以很容易地将你的构建拆分为多个可重用的模块,最后再进行组装,但不要强制地进行模块的拆分。 不要把原本在一起的东西强行分开(比如在你的项目结构里),从而避免让你的构建变成一场噩梦。 最后,你可以创建一个结构良好,易于维护,易于理解的构建。
Gradle 允许你在构建执行的整个生命周期,对它的核心配置及执行行为进行监视并自定义。
Gradle 有非常良好的扩展性。 从简单的单项目构建,到庞大的多项目构建,它都能显著地提升你的效率。 这才是真正的结构化构建。通过最先进的增量构建功能,它可以解决许多大型企业所面临的性能瓶颈问题。
Gradle 对多项目构建的支持非常出色。项目依赖是首先需要考虑的问题。 我们允许你在多项目构建当中对项目依赖关系进行建模,因为它们才是你真正的问题域。 Gradle 遵守你的布局。
Gradle 提供了局部构建的功能。 如果你在构建一个单独的子项目,Gradle 也会帮你构建它所依赖的所有子项目。 你也可以选择重新构建依赖于特定子项目的子项目。 这种增量构建将使得在大型构建任务中省下大量时间。
不同的团队喜欢用不同的方式来管理他们的外部依赖。 从 Maven 和 Ivy 的远程仓库的传递依赖管理,到本地文件系统的 jar 包或目录,Gradle 对所有的管理策略都提供了方便的支持。
Ant tasks 是最重要的。而更有趣的是,Ant projects 也是最重要的。 Gradle 对任意的 Ant 项目提供了深度导入,并在运行时将 Ant 目标(target)转换为原生的 Gradle 任务(task)。 你可以从 Gradle 上依赖它们(Ant targets),增强它们,甚至在你的 build.xml 上定义对 Gradle tasks 的依赖。Gradle 为属性、路径等等提供了同样的整合。
Gradle 完全支持用于发布或检索依赖的 Maven 或 Ivy 仓库。 Gradle 同样提供了一个转换器,用于将一个 Maven pom.xml 文件转换为一个 Gradle 脚本。Maven 项目的运行时导入的功能将很快会有。
Gradle 能适应你已有的任何结构。因此,你总可以在你构建项目的同一个分支当中开发你的 Gradle 构建脚本,并且它们能够并行进行。 我们通常建议编写测试,以保证生成的文件是一样的。 这种移植方式会尽可能的可靠和减少破坏性。这也是重构的最佳做法。
Gradle 的构建脚本是采用 Groovy 写的,而不是用 XML。 但与其他方法不同,它并不只是展示了由一种动态语言编写的原始脚本的强大。 那样将导致维护构建变得很困难。 Gradle 的整体设计是面向被作为一门语言,而不是一个僵化的框架。 并且 Groovy 是我们允许你通过抽象的 Gradle 描述你个人的 story 的黏合剂。 Gradle 提供了一些标准通用的 story。这是我们相比其他声明性构建系统的主要特点。 我们的 Groovy 支持也不是简单的糖衣层,整个 Gradle 的 API 都是完全 groovy 化的。只有通过 Groovy才能去运用它并对它提高效率。
Gradle Wrapper 允许你在没有安装 Gradle 的机器上执行 Gradle 构建。 这一点是非常有用的。比如对一些持续集成服务来说。 它对一个开源项目保持低门槛构建也是非常有用的。 Wrapper 对企业来说也很有用,它使得对客户端计算机零配置。 它强制使用指定的版本,以减少兼容支持问题。
Gradle 是一个开源项目,并遵循 ASL 许可。
进入gradle官网:https://gradle.org,点击【Install Gradle】
进入页面后,可以看到installing manually手动安装,有binary-only和complete两种安装包,complete完整一些,包括文档和相应的源。
这里我选择了binary-only下载,下载并解压到自己想要的目录,这里我解压到我的D目录:D:\
添加环境变量GRADLE_HOME和path,如下所示
GRADLE_HOME:D:\F:\TEST\gradle-6.1-bin\gradle-6.1
path:%GRADLE_HOME%\bin
添加环境变量完成后,打开cmd命令模式,输入gradle -v,若展示gradle基本信息,则表明安装成功
gradle的目录其实与maven的目录结构是一致的,大体如下所示:
其中:
直接使用命令的方式进行创建。
创建一个空文件夹并进入目录
依次输入如下命令:
gradle init
选择项目的类型
选择要使用的语言
选择测试框架
选择脚本编写的语言
输入项目名称、包名,默认是我们刚才进入的文件夹名称 ,即可。
使用工具直接创建,在IEDA中配置gradle后创建项目。
gradle构建中的两个基本概念是项目(project)和任务(task),每个构建至少包含一个项目,项目中包含一个或多个任务。在多项目构建中,一个项目可以依赖于其他项目;类似的,任务可以形成一个依赖关系图来确保他们的执行顺序。
Gradle的构建生命周期分为初始化,配置,执行三个阶段。
初始化阶段主要是读取settings.gradle 文件,用于确定哪些项目参与构建,并创建Project实例;如多个项目构建时,通常setting.gradle内容如下:
include "projectA","projectB","projectC"
//表示参与构建的项目有projectA,projectB,projectC
4.1.2. 配置阶段
配置阶段主要是为每个项目的build.gradle文件配置project对象;主要是生成task的依赖关系跟执行图。
执行阶段主要是根据gradle命令和传入的参数创建并执行任务。
Gradle构建脚本描述一个或多个项目。每个项目都由不同的任务组成。任务是构建执行的一项工作,主要包括任务动作和任务依赖,任务动作定义了一个最小的工作单元,可以定义依赖,动作序列和执行条件;Gradle保证这些任务按其依赖项的顺序执行,并且每个任务只执行一次。这些任务可以抽象成一个有向无环图。Gradle会在执行任务之前构建完整的依赖关系图,这就是Gradle的核心思想。
任务是构建脚本build.gradle中的关键字,任务的定义模式大体如下所示:
task testTask{
doLast {
println 'I am a tester'
}
}
#doLast 语句可以使用快捷方式(表示符号 <<)来简化此任务
#上述语句等同于:
task testTask << {
println 'I am a tester'
}
如下,在终端中输入如下命令执行task
gradle -q testTask
要将一个任务依赖另一个任务,在开始这个任务之前,先完成依赖的任务。 每个任务都使用任务名称进行区分。
任务的依赖第一种填写方式,我们可以直接在定义任务是指定需要依赖的任务,其中需要注意如下两点:
task testTask {
doLast {
println 'I am a tester'
}
}
//被依赖的任务可以定义在之前或者之后
//如果被依赖的任务定义在之后,也叫做延迟依赖,
//延迟依赖下,被引用的的任务名需要加入引号,所以通常我们把引号加上就好了
task testDepend(dependsOn:'testTask') {
doLast {
println 'I do test job'
}
}
如下,在终端中输入如下命令执行任务:
gradle -q testDepend
依赖的第二种填写方式,分别编写完任务后,在末尾写入依赖语句:
task testTask {
doLast {
println 'I am a tester'
}
}
task testDepend {
doLast {
println 'I do test job'
}
}
testDepend.dependsOn testTask
如下,在终端中输入如下命令执行任务:
gradle -q testDepend
如果要查找在构建文件中定义的任务,则必须使用相应的标准项目属性。这意味着每个任务都可以作为项目的属性,使用任务名称作为属性名称。
如下在build.gradle中定义了一个任务xiong,那么我们可以通过如下方式查找任务
task wendy
println wendy.name
println project.wendy.name
如下,在终端中输入如下命令执行任务:
gradle -q wendy
当然我们也可以由其任务集合(tasks)来查找。要引用另一个项目中的任务,应该使用项目路径作为相应任务名称的前缀。
task wendy
println tasks.wendy.name
println tasks['wendy'].name
如下,在终端中输入如下命令执行任务:
gradle -q wendy
Gradle构建脚本定义了构建项目的过程; 每个项目包含一些依赖项和一些发布项。依赖项意味着支持构建项目所需要的东西,比如构建时需要的jar包等。发布项表示项目的结果,如测试类文件和构建文件,如war文件。
如下是一个依赖管理简要图,其流程主要为:
传递依赖
B依赖A,如果C依赖B,那么C依赖A。
几乎所有的基于JVM的软件项目都需要依赖外部类库来重用现有的功能。自动化的依赖管理可以明确依赖的版本,可以解决因传递性依赖带来的版本冲突。
版本冲突
如下hibermate-core-3.6.3.Final.jar依赖的hibermate-core-3.2.0.Final.jar包中依赖了slf4i-api-1.5.8.jar,所以按传递依赖的性质,hibermate-core-3.6.3.Final.jar会依赖slf4i-api-1.5.8.jar
而hibermate-core-3.6.3.Final.jar本身又依赖了slf4i-api-1.6.1.jar,所以会导致版本冲突
但是因为gradle默认会依赖最高版本的jar包,所以gradle默认是不会出现版本冲突的.
在gradle中,一个group、name、version确定一个唯一的jar包,如在build.gradle文件中配置如下依赖,定义了两个依赖项,一个是Hibernate core 3.6.7,第二个是Junit 4.0和更高版本。
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
依赖关系配置只是定义了一组依赖关系,然后我们根据指定的依赖声明从Web下载外部依赖关系。如下是依赖阶段不同的标准配置:
依赖的类型有很多种,其中有一种类型称之为外部依赖。这种依赖由外部构建或者储存在不同的仓库中,例如 Maven 中央仓库或 Ivy 仓库中抑或是本地文件系统的某个目录中。
如下就定义了一个外部依赖,在进行构建时会从仓库中去查找该依赖:
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
}
外部依赖包含 group,name 和 version 几个属性。根据选取仓库的不同,group 和 version 也可能是可选的。
当然,也有一种更加简洁的方式来声明外部依赖。采用:将三个属性拼接在一起即可。"group:name:version"
dependencies {
compile 'org.hibernate:hibernate-core:3.6.7.Final'
}
在添加依赖关系时, Gradle在存储库中查找它们。 存储库只是文件的集合,按group,name和version来组织构造; 默认情况下,Gradle不定义任何存储库,我们必须至少明确地定义一个存储库。如下我们先定义了一个自定义的maven仓库,然后是本地的maven仓库,最后是maven的中央仓库,在查找依赖时依次从上到下进行查找。
repositories {
//自定义maven仓库,也就是maven私服
maven {
url:'xxxx'
}
mavenLocal() //本地仓库
mavenCentral() //公共仓库-maven中央仓库
jcenter() //公共仓库-jcenter仓库
}
在企业项目中,包层次和类关系比较复杂,把代码拆分成模块通常是最佳实践,这选哟清晰的划分功能边界,比如把业务逻辑和数据持久化拆分开来,项目符合高内聚低耦合时,模块化就不安的很容易,这是也是多项目的由来。
依赖管理配置也被用于发布文件我们称之为打包发布或发布。
插件对于打包提供了完美的支持,所以通常而言无需特别告诉 Gradle 需要做什么。但是你需要告诉 Gradle 发布到哪里。这就需要在 uploadArchives 任务中添加一个仓库。
发布到 Maven 仓库你需要 Maven 插件的支持,当我们使用:gradle uploadArchives 命令时,Gradle 构建并上传你的 jar 包,同时产生 pom.xml 一起上传到下方指定的maven仓库。
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
repository(url: "file://localhost/xxx/")
}
}
}
当我们使用:gradle uploadArchives 命令时,Gradle 便会构建并上传你的 jar 包,同时会生成一个 ivy.xml 一起上传到如下指定的ivy仓库:
uploadArchives {
repositories {
ivy {
credentials {
username "username"
password "password"
}
url "http://repo.mycompany.com"
}
}
}
Gradle 在它的核心中有意地提供了一些小但有用的功能,用于在真实世界中的自动化。所有有用的功能,例如以能够编译 Java 代码为例,都是通过插件进行添加的。插件都认为是被应用,通过 Project.apply() 方法来完成。
Java 插件向一个项目添加了 Java 编译、 测试和 building 的能力。它是很多其他 Gradle 插件的基础服务。
Java 插件定义了两个标准的源集,分别是 main 和 test。main 源集包含你产品的源代码,它们将被编译并组装成一个 JAR 文件。test 源集包含你的单元测试的源代码,它们将被编译并使用 JUnit 或 TestNG 来执行。
在build.gradle文件中Java插件的引入如下所示:
apply plugin: 'java'
如上是使用短名称的方式,我们也可以使用完整的名称方式:
apply plugin: org.gradle.api.plugins.JavaPlugin
或者
apply plugin: JavaPlugin
同时Java 插件向你的项目添加了大量的任务,具体可参考官网或者地址:
https://www.w3cschool.cn/gradle/q9bp1hum.html
Groovy 的插件继承自 Java 插件并添加了对 Groovy 项目的支持。它可以处理 Groovy 代码,以及混合的 Groovy 和 Java 代码,甚至是纯 Java 代码(尽管我们不一定推荐使用)。该插件支持联合编译,可以任意地混合及匹配 Groovy 和 Java 代码各自的依赖。例如,一个 Groovy 类可以继承自一个 Java 类,而这个 Java 类也可以继承自一个 Groovy 类。这样一来,我们就能够在项目中使用最适合的语言,并且在有需要的情况下用其他的语言重写其中的任何类。
其在build.gradle文件中的添加方法如下:
apply plugin: 'groovy'
同样groovy插件也向Project中添加了大量的任务,具体请参考官网或者地址:
https://www.w3cschool.cn/gradle/q9bp1hum.html
War 的插件继承自 Java 插件并添加了对组装 web 应用程序的 WAR 文件的支持。它禁用了 Java 插件生成默认的 JAR archive,并添加了一个默认的 WAR archive 任务。
apply plugin: 'war'
同样war插件也向Project中添加了大量的任务,具体请参考官网或者地址:
https://www.w3cschool.cn/gradle/q9bp1hum.html
Jetty 插件继承自 War 插件,并添加一些任务,这些任务可以让你在构建时部署你的 web 应用程序到一个 Jetty 的 web 嵌入式容器中。
apply plugin: 'jetty'
同样jetty插件也向Project中添加了大量的任务,具体请参考官网或者地址:https://www.w3cschool.cn/gradle/xg9o1hu7.html
序号
命令
描述
1
gradle -q taskName1 taskName2
-q表示获取构建信息,执行具体的任务,可以指定多个任务
2
gradle tasks
列出所有任务列表
3
gradle build
Gralde 会编译并执行单元测试,并且将 src/main/* 下面 class 和资源文件打包
4
gradle build -x taskName
执行构建命令,并排除taskName任务
5
gradle build -continue
默认情况下Gradle将在任何任务失败时立即中止执行。如果我们希望即使发生故障,也可以继续执行,使用-continue
6
gradle clean
删除 build 目录以及所有构建完成的文件
7
gradle assemble
编译并打包 jar 文件,但不会执行单元测试。一些其他插件可能会增强这个任务的功能。例如,如果采用了 War 插件,这个任务便会为你的项目打出 War 包
8
gradle check
编译并测试代码。一些其他插件也可能会增强这个任务的功能。例如,如果采用了 Code-quality 插件,这个任务会额外执行 Checkstyle
9
gradle -q [projectName] projects
列出所选项目及其子项目的项目层次结构
10
gradle –q [projectName] dependencies
提供所选项目的依赖关系的列表
11
gradle -q [projectName] properties
提供所选项目的属性列表
12
gradle -p projectName -x test build
多项目中指定需要构建的项目,并排除测试构建
13
gradle taskName -m
查看任务taskName的子任务,我们可以通过这个命令查看任务的包含关系
#比如项目:http://gitlab.xx.com/projectA
git clone -b develop http://gitlab.xx.com/projectA/port.git
cd port
#这是因为项目的问题,在./gradle/wrapper目录下缺少了gradle-wrapper.jar,所以我们只#要新建一个gradle项目,然后报新建项目的gradle-wrapper.jar放入./gradle/wrapper即可
.\gradlew -p projectName -x test build
问题点:
1.当从gitlab中下载了代码之后,执行gradle tasks时提示wrapper任务已存在
这是因为开发的build.gradle配置脚本中,配置了一个wrapper的任务,如下:
而配置使用的wrapper刚好与本地的wrapper版本是不一致的,所以解决方法就是执行时,使用的命令是gradlew,而不是gradle。
2.构建时总是提示某个版本不存在,实际上就是因为按照gradle仓库配置的路径去寻找依赖,可能因为网速或者访问国外网站很慢的原因导致依赖包最终没有下载下来。
解决方法是在仓库中先加入如下的配置在国内镜像查找。
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
3.在windows的cmd命令行中使用gradlew.bat build命令时提示: org.gradle.wrapper.GradleWrapperMain
解决方法:https://github.com/mcxiaoke/gradle-packer-plugin/issues/1,也就是新建一个android工程的时候在gradle/wrapper里面默认会有一个gradle-wrapper.jar文件,把这个拷贝到你项目中的gradle/wrapper中。
4.出现如下错误的原因是因为没有Scala插件导致的,所以我们只要在idea中装入Scala插件就行了。
5.在idea工具中,gradle无法下拉出具体的任务,如下:
这可能是因为项目中构建所需要的依赖包没有完全下载完导致的,解决方法可以参照第2点,下载完所有的依赖包应该就可以解决此问题了,或者我们开启VPN,让我们的网络可以访问国外网站,这样也能处理此问题。
按如下刷新按钮进行刷新,重新下载依赖包,下载完成之后就可以下拉任务了:
整理了一份思维导图,希望对大家有所帮助:
手机扫一扫
移动阅读更方便
你可能感兴趣的文章