首页 > 代码库 > Gradle入门笔记

Gradle入门笔记

      引言:Gradle是一种构建工具,它抛弃了基于XML的构建脚本,取而代之的是采用一种基于Groovy的内部领域特定语言。

 

      Groovy是一种基于JVM的敏捷开发语言,其开发效率比java高,但对比特殊的编译性语言Java( Java文件将编译成JVM可辨识的二进制文件.class )groovy作为一个动态的脚本语言,由于元编程特性(元编程简单来说就是,编写运行时操作语言构建的代码,用代码操作代码)groovy对比java效率低。下图为groovyjavademo效率对比图:

  技术分享

             附上对比图来源链接:https://dzone.com/articles/java-7-vs-groovy-21
 
      尽管Groovy效率比java低,Groovy的开发效率及其基于JVM带来的跨平台性的优势却不可忽视,同时Gradle是为Java项目服务,考虑至此,Gradle开发团队选用了Groovy为开发语言(个人理解)。
下面才是gradle的官方解释(=_=!!):
      "我们认为在脚本构建时,内部基于 XML 的 DSL(基于一个动态语言)优势是巨大的. 有许多动态语言在那里, 我们为什么选择 Groovy? 答案在于 Gradle 的运行环境. 虽然 Gradle 是以一个多用途的构建工具为核心,它的重点是Java项目. 在这样的项目中, 显然团队每个成员都了解 Java. 我们认为构建应尽可能对所有团队成员都是透明的, 所以选择了 Groovy.
      你可能会说,为什么不直接使用 Java 作为构建脚本的语言. 我们认为这是一个有效性的问题. 对于你的团队, 它要有最高的透明度和最低的学习曲线, 也就是说容易掌握. 但由于 Java 的限制, 这样的构建语言不会那么完美和强大. 如 Python,Groovy 或 Ruby 语言都可以有更高的效率. 我们选择了 Groovy 是因为它给 Java 开发人员提供了迄今为止最大的透明度. 其基本的符号和类型与 Java 是一样的,其封装结构和许多其他的地方也是如此.
      对于那些同样分享 Python 或 Ruby 知识的 Java 团队将会很乐意学习它. Gradle 的设计非常适合在 JRuby 和 Jython 中创建另一个构建脚本引擎. 它只是目前开发的优先级里. 我们十分支持任何人来做贡献, 创建额外的构建脚本引擎."
 
     在理解Gradle是干什么之前,先去粗略了解重温一下几个插件工具:
1. Apache Ant:是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发。
2.Apache Ivy:Apache Ant 下的一个子项目,Apache Ivy是一个优秀的管理(记录、跟踪、解析和报告)项目依赖的工具,提供了强大的依赖管理功能,可与Apache Ant紧密集成。可以说ant负责项目的build,而Ivy负责项目内部的依赖。
3.Apache Maven:模块化项目构建工具(Building a Project )。它能够管理依赖、构建周期、测试、打包并且在仓库中发布你的制品。同时拥有了ant与ivy的功能。
 
     前面啰嗦了一大推,把Groovy,Apache ant,Apache ivy,Apache maven都提了一遍,就是为了现在总结使用Gradle的优势(以下摘抄修改自维基百科---Gradle)
  • 自动处理包相依关系 - 取自 Maven Repos , Ivy 的概念
  • 自动处理布署问题 - 取自 Ant 的概念
  • 条件判断写法直觉 - 使用 Groovy 语言(简单理解动态脚本语言,开发效率高)
 
      过去 Java 开发者常用 Maven 和 Ant 等工具进行封装布署的自动化,或是两者兼用,不过这两个包彼此有优缺点,如果频繁改变相依包版本,使用 Ant 相当麻烦,如果琐碎工作很多,而Maven 功能不足,且两者都使用 XML 描述,相当不利于设计 if、switch 等判段式,即使写了可读性也不佳,在我们团队开发中,基本都使用了Maven管理依赖,而由于历史问题,项目中的依赖多多少少存在不合理的地方,修改起来怕是动一发而牵全身,而 Gradle 改良了过去 Maven、Ant 带给开发者的问题,功能更全,使用便更加灵活,为此,这也正是我所在开发团队一起学习Gradle的原因与动力。
     
      
      以下正式开始学习如何搭建第一个使用Gradle的java项目
 

Gradle安装

基于开发团队日常基本是使用windows操作系统开发,因此介绍此笔记暂时基于windows而写。
 
Gradle的安装条件:JDK6及以上(Gradle自带Groovy库,Gradle会忽略此前安装的Groovy)。
 
1. 总得先下载Gradle先吧,点击这里 http://www.gradle.org/downloads 。很慢?对的,很慢。 考虑到官网下载速度很慢很龟速,我特意把gradle-3.4放上oss中。
地址 : http://sari.oss-cn-beijing.aliyuncs.com/gradle-3.4-all.zip
 
2.下载完后,在指定路径解压,添加一个 GRADLE_HOME 环境变量来指明 Gradle 的安装路径,再添加 %GRADLE_HOME%/bin 到 PATH 环境变量中.。正常的话,现在就可以运行Gradle了。测试是否成功安装配置的方法是,直接上图吧。
技术分享

 

 
     跳过最简单的HelloWorld的demo,我们直接跑起一个spring boot的多项目的build。
网上的教程,乃至官方文档在建立项目介绍上是选择跳过的,因此一开始,我查看了很多教程都是模模糊糊的,教程中都是在build.gradle中写上applu plugin ‘java‘ 然后就一下子出现了一个完整的java项目结构(后面仔细介绍build.gradle),摸索思考了下,人类历史最伟大的进步便是学会使用工具,而我们手上正有IDE这伟大的工具,而IDE正正让我跳过了官方文档的第一个坑。我们团队应该大多都是使用IDEA进行开发的,因此我下面的Demo都是利用idea的。
 
1.使用IDEA,new project,此时惊奇的发现IDEA集成了Gradle
 技术分享

 

 

2.填写好点击下一步

 技术分享

3.此时应该发现Gradle的建立和Maven相差无几,把上面的两项勾上,让IDE去做它该做的事情,点击下一步。

技术分享

4.继续点击下一步。

 

 

 技术分享

 

 

5.此时我们发现一个熟悉的java项目结构出现了

 

技术分享

 

 

6.点击打开build.gradle,下面大致说明一下此文件的意义

技术分享

 

 

在Gradle中,有两个基本概念:项目和任务。请看以下详解:
项目是指我们的构建产物(比如Jar包)或实施产物(将应用程序部署到生产环境)。一个项目包含一个或多个任务。
任务是指不可分的最小工作单元,执行构建工作(比如编译项目或执行测试)。

build.gradle是gradle项目的构建脚本,里面指定了项目与任务。紧接着仔细说一下IDEA构建出项目后build.gradle默认的语句含义。

group ‘JryLearnGradle‘,version ‘1.0-SNAPSHOT‘ :
build名,版本号。

apply plugin: ‘java‘ :
Gradle与Maven一样,特性都是由plugin提供的,Gradle为我们提供了许多有用的插件,apply plugin :‘java‘ ,则是把gradle为java开发写的插件源码引用到build.gradle中(gradle中的plugin都是用groovy写好的代码)

repositories {
mavenCentral()
} :
Gradle仓库可以使用maven或ivy的仓库,我们团队基本使用maven,而IDEA默认使用了Central Maven 2的仓库,而加入maven仓库,gradle提供了三种选择给我们使用,分别是:
mavenCentral()别名,表示依赖是从Central Maven 2 仓库中获取的。
jcenter()别名,表示依赖是从Bintary’s JCenter Maven 仓库中获取的。
mavenLocal()别名,表示依赖是从本地的Maven仓库中获取的。
我们可以更改代码 mavenCentral() 选择不用的方式,当然gradle还提供了另外一种方式让我们构建依赖仓库来源,那便是url的方式,下面是使用url方式的方法:
repositories {
     maven {
http://maven.aliyun.com/nexus/content/groups/public        url ""
     }
}

dependencies {
compile group: ‘foo‘, name: ‘foo‘, version: ‘0.1‘
testCompile group: ‘junit‘, name: ‘junit‘, version: ‘4.11‘
} :
这处申明外部依赖,这些依赖存放在外部仓库中。一个外部依赖可以由以下属性指定:
group属性指定依赖的分组(在Maven中,就是groupId)。
name属性指定依赖的名称(在Maven中,就是artifactId)。
version属性指定外部依赖的版本(在Maven中,就是version)。

testCompile是test需要的外部依赖,而compile则是项目运行需要的依赖声明,依赖的声明可以使用快捷方式:
dependencies {
compile ‘foo:foo:0.1‘
testCompile ‘junit:junit:4.11‘
}

默认的build.gradle文件也就解释完了,后面再一点点补充,现在回到我们跑demo的目的,我们是为了建立一个多项目的Spring boot,因此我们需要为SpringBootInGradle添加module,操作和maven差不多。

额外打开一下setting.gradle文件,发现里面就一句 rootProject.name = ‘SpringBootInGradle‘ ,就是project,没啥其他东西,先不管,往后操作。

 

7.右键项目名,new module

 

技术分享

 

8.分别建立JryCoreJryBasicServermodule,点击next

技术分享

 

9.此时我们的项目结构如下图

 

技术分享

 

此时发现IDE实在太好用了,什么都自动为我们做好了,但作为一个学习者,还是得知道IDE在这期间究竟为我们做了什么,先来看看module中的build.gradle吧
group ‘JryLearnGradle‘
version ‘1.0-SNAPSHOT‘
 
apply plugin: ‘java‘
 
sourceCompatibility = 1.5
 
repositories {
mavenCentral()
}
 
dependencies {
testCompile group: ‘junit‘, name: ‘junit‘, version: ‘4.11‘
}
和一开始的没什么区别,其他几个builg.gradle也是如此,再来看看被我们一直忽略的settings.gradle,此时发现settings.gradle多了两行代码:
rootProject.name = ‘SpringBootInGradle‘
include ‘JryCore‘
include ‘JryBasicServer‘
而include的两个module正是我们刚刚添加的,由此推倒,我们需要为一个project增加module只需要在project中的setting.gradle写入include ‘xxxx’ 。
此时再去看看官方文档的做法(https://docs.gradle.org/current/userguide/build_lifecycle.html):
 
 技术分享

 

 

   很简练,就是和我们推倒的一样,接着干。

 

      此时发现,project中有三个build.gradle,里面的东西都一模一样,重复,如论从哪点考虑,我们作为一个多projectproject,应该有module通用的依赖。接下来我们要做的是做到moduleparent中的build.gradle配置。

 

9.module中重复的配置转移到根项目的构建脚本,build.gradle修改添加代码,如下图:

 技术分享

此时发现两段内容代码都是一样的,还是重复,再修改,如下图:

技术分享

 

 

第一个方式是针对某个project的操作,第二个是对根项目下的子项目的通用配置方式

 

如果是多项目构建中的所有项目共享,可以在根项目中的build.gradle加入allproject{}

 

10.JryBasicServer中建立一个类HelloWorld,类中定义方法getString()

技术分享

 

11.修改根项目build.gradle文件,如下图

 

技术分享

build.gradle中除compile project(‘:JryBasicServer‘),其他都是前面解释过的语句,而compile projec的意思便是在JryCore中引入JryBasicServer项目,在打包时,gradle会先把JryBasicServer加载完后再到JryCore。
 
build.gradle修完完后,点击refresh all gradle projects,gradle将下载依赖,此时应该发现gradle从https://repo1.maven.org/maven2中拉取依赖,这肯定不是我们想要的,国内墙太厚,gradle能不能像maven一样,引用阿里的私库呢?
能。
(1)我们先新建一个init.gradle文件,里面内容为:
 
allprojects{
repositories {
def REPOSITORY_URL = ‘http://maven.aliyun.com/nexus/content/groups/public‘
all { ArtifactRepository repo ->
def url = repo.url.toString()
if ((repo instanceof MavenArtifactRepository) && (url.startsWith(‘https://repo1.maven.org/maven2‘) || url.startsWith(‘https://jcenter.bintray.com‘))) {
project.logger.lifecycle ‘Repository ${repo.url} replaced by $REPOSITORY_URL .‘
remove repo
}
}
maven {
url REPOSITORY_URL
}
}
}
 
(2)把init.gradle文件放置在C:\Users\USER_NAME\.gradle中,此时gradle下载依赖时将会先执行init.gradle文件,此时发现下载依赖速度总算正常。
 
这里提一下init.gradle的作用和加载顺序
 
先来简单介绍一下init.gradle这个文件的作用。
  • 它可以用来建立公司内部的配置,如定义公司内部的仓库地址。
  • 它可以用来配置一些全局属性,比如配置持续集成服务器的地址等配置。
  • 它可以用来提供构建所需要的用户的个人信息,如仓库或数据库的用户名和密码。
  • 它可以用来定义开发者机器的环境,比如定义jdk安装在什么位置,android sdk安装在什么位置等等。
  • 最重要的功能之一,它可以用来注册一些监听器。比如监听Gradle事件的发生,做一些额外的操作,例如需要对某个项目构建前和构建后做一些操作,又例如对项目的依赖做检测,检测是否含有snapshot包,在release构建中一般来说是禁止依赖snapshot包的,所以这时候就可以扔出一个异常。
  • 重定向日志。我们可以将gradle默认的日志进行重定向,甚至我们可以不输出默认日志,自定义如何输出gradle产生的日志信息。
 
init.gradle的加载顺序:
1.加载USER_HOME/.gradle/init.gradle文件
2.加载USER_HOME/.gradle/init.d/目录下的以.gradle结尾的文件
3.加载GRADLE_HOME/init.d/目录下的以.gradle结尾的文件
 
11.依赖齐全后,在JryCode新建类PrintHelloController,内容如下
技术分享

 

12.接下来就是run啦,成功跑起后,访问localhost:8080
 
技术分享

 

 

 此时一个多projectSpringBootHelloWorld就完成了,需要打包只需点击Gradle projectsbuild

技术分享

成功build后,我们可以发现在libs中有我们需要的jar包了。

 

一个简单的demo就跑完了,以上都是走马观花式的操作,下面来分析一下Gradle的原理与总结吧。

 

 

深入理解Gradle背后的内容

 

 

 

在理解Gradle内容前,我们需要先理解一下何谓DSL。

 

DSL,领域特定语言,其基本思想是“求专不求全”,不像通用目的语言那样目标范围涵盖一切软件问题,而是专门针对某一特定问题的计算机语言。而Martin Fowler将DSL分为两类:外部DSL和内部DSL。外部DSL是一种独立的可解析的语言,举一个最常见的是例子,SQL,它专注于数据库的操作。内部DSL是通用语言所暴露的用来执行特定任务的API,它利用语言本身的特性,将API以特殊的形式(或者格式)暴露出来的。

 

总结一下,外部DSL是一种特定的独立语言,内部DSL是通用语言为实现特殊目的提供的API。

 

 

 

Gradle开发团队为了使用Gradle更好的构建描述,为Gradle提供了一套内部DSL,语言正是基于上文提及到的Groovy,理解了内部DSL,就能知道我们在跑demo时用到的各种dependenices{},project{},等等语句,底层其实就是调用用groovy代码封装好的api方法,继而也能理解Gradle中的plugin其实也就是用groovy写好的代码块,apply一个plugin,其实也相当于我们的开发的import。

 

 

 

了解了Gradle底层的实现,就应该来学习Gradle的设计思想。

 

Gradle是按照DDD(领域驱动设计)的思想设计和开发的,其三个领域对象:Project、Task、Action。而官方文档是这么说的,一个构建是由多个project组成,一个project是由多个task组成,task之间的依赖关系,构成了整个构建的流水线。下面仔细说一下三个领域对象的意义。

 

Project: Project是Gradle最重要的一个领域对象,我们写的build.gradle脚本的全部作用,其实就是配置一个Project实例。

 

Task:Gradle的Task等同于Ant的Target。 我们跑demo时在build.gradle写的dependenices{},project{},等等就是一个个的task,task是闭包的。

 

Action:Task可以包含n个Action,Task提供了doFirst和doLast方法来给自己添加Action,如下面的例子一样。

 

.task myTask {  

 

   doFirst {  

 

       println ‘hello‘  

 

     }  

 

    doLast {  

 

        println ‘world‘  

 

     }  

 

 }  

 

 

 

稍微总结一下上文,通过我们跑的demo,结合刚刚介绍,Gradle没有一开始的神秘,我们其实可以把它理解为api,它的配置文件其实就是我们一直编写的代码,我们要使用某功能的时候,按往常一样,去看一下官方API就行了

 

 

 

明白了Gradle底层设计和设计思想,接下来补充一下Gradle运行的生命周期。

 

Gradle的生命周期

 

1. Initialization -初始化阶段,初始化阶段会执行项目根目录下的settings.gradle文件,来分析哪些项目参与构建。

 

2. Configuration -配置阶段,配置阶段会去加载所有参与构建的项目的build.gradle文件,会将每个build.gradle文件实例化为一个Gradle的project对象。然后分析project之间的依赖关系,下载依赖文件,分析project下的task之间的依赖关系。

 

3. Execution -执行阶段,执行阶段来执行具体的task。

 

 

 

 

 

总结Gradle

 

Gradle对比Maven,最直观的便是,Maven的POM用XML写,内容标准,以致有所古板,而Gradle的配置文件则使用groovy编写,用代码编写的Gradle更加灵活,同时也更加简洁,而其提供的plugin也为其提供强大的功能。

 

Gradle对比Ant,Ant同样使用XML,XML文件臃肿庞大,Gradle的DSL就显得更加灵活。

 

前面两面两点都是说Gradle的优势,约定人性化,灵活性更高,但这里有必要提一下,就效率而言,Gradle与Maven和Ant并相差无几。毕竟没有完美的东西。

 

 

 

 

 

以上都是我个人在学习Gradle的笔记,内容不全,不能顾全全部,gradle还有很多很多没接触到的地方没提及到,后面再有心得,一点一点补充。

 

 

 

Gradle入门笔记