基本介绍、常用指令、项目目录、项目应用
Groovy语法、整合IDEA、搭建web工程、项目部署
生命周期、钩子函数、项目发布、配置文件、Project与Task、Gradle插件
整合SSM多模块、微服务实战
Ant:2000年Apache推出的纯Java编写构建工具,通过xml build.xml文件管理项目
优点:使用灵活,速度快(快于gradle和maven),
缺点:At没有强加任何编码约定的项目目录结构,开发人员需编写繁杂XL文件构建指令对开发人员是一个
挑战。
Maven: 2004年Apache组织推出的再次使用xml文件pom.xml虹管理项目的构建工具.
优点:遵循一套约定大于配置的项目目录结构,使用统一的GAV坐标进行依赖管理,侧重于包管理。
缺点:项目构建过程僵化.配置文件编写不够灵活、不方便自定义组件构建速度慢于d!e,
Gradle:2012年Google推出的基于Groovy语言的全新项目构建工具,集合了Ant和Maven各自的优势。
优点:集Ant脚本的灵活性+Mavn约定大于配置的项目目录优势,支持多种远程仓库和插件,侧重于大项目
构建。
缺点:学习成本高、资料少、脚本灵活、版本兼容性差等。
allprojects {
repositories {
mavenLocal()
maven {name "Alibaba" ; url 'https://maven.aliyun.com/repository/public'}
maven {name "Bstek" ; url "https://nexus.bsdn.org/content/groups/public/"}
mavenCentral()
}
buildscript {
repositories {
maven {name "alibaba"; url :"https://maven.aliyun.com/repository/public "}
maven {name "Bstek" ; url "https://nexus.bsdn.org/content/groups/public/"}
maven {name "M2" ; url "https://plugins.gradle.org/m2/"}
}
}
常用gradle指令 | 作用 |
---|---|
gradle clean | 清空build目录 |
gradle classes | 编译业务代码和配置文件 |
gradle test | 编译测试代码,生成测试报告 |
gradle build | 构建项目 |
gradle build -x test | 跳过测试构建项目 |
注意:gradle的指令要在含有build.gradle的目录执行。
init.gradle可以在编译启动前执行这个脚本,比如配置上镜像地址
有几种方式使用init.gradle呢
1. 在命令行指定文件,例如: gradle --init-script yourdir/init.gradle -q taskName.你可以多次输入此命
令来指定多个init文件
3. 把init.gradle文件放到USER_HOME/,gradle/目录下
4. 把以.gradle结尾的文件放到USER_HOME/.gradle/init.d/目录下
5. 把以.gradle结尾的文件放到GRADLE_HOME/init.d目录下
如果存在上面的4种方式的2种以上,gradle会按上面的1-4序号依次执行这些文件,如果给定目录下存在多个
init脚本,会按拼音a-z顺序执行这些脚本,每个nit脚本都存在一个对应的adle实例,你在这个文件中调用的
所有方法和属性,都会委托给这个gradle实例,每个init脚本都实现了Seript接口。
仓库地址说明:
mavenLocal():指定使用本地maven本地仓库,而本地仓库在配置maven时settings文件指定的仓库位置。
maven {url位置},指定maven仓库,一般用私有仓库地址或其他第三方库。比如阿里云镜像地址
mavenCentral() 这是Maven的中央仓库,无需配置,直接声明就可以使用。
jcenter(): Jcenter中央仓库,实际也是用的maven搭建,但相比Maven仓库更友好,通过cdn分发,并且支持https访问,在新版本中已经废弃,替换为了mavenCentral()
总之,gradle可以通过指定仓库地址为本地maven仓库地址和远程仓库地址相结合的方式,避免每次都会去远程仓库下载依赖库·这种方式也有一定的问题,如果本地maven仓库有这个依赖,就会从直接加载本地依赖,如果本地仓库没有该依赖,那么还是会从远程下载·但是下载的jar不是存储在本地naven仓库中,而是放在自己的缓存目录中,默认在USER_HOME/.gradle/caches
目录,当然如果我们配置过GRADLE_USER_HOME环境变量,则会放在GRADLE_USER_HOME/caches目录,那么可不可以将gradle caches指向maven repository。我们说这是不行的,caches下载文件不是按照maven仓库中存放的方式·
阿里云开发者镜像查询地址:https://developer.aliyun.com/mvn/guide
Gradle Wrapper实际上就是对Gradle的一层包装,用于解快实际开发中可能会遇到的不同的项目需要不同版本的Gradle问题。例如:把自己的代码共享给其他人使用,可能出现如下情况:
- 对方电脑上没有安装gradle
- 对方电脑上安装了gradle,但是版本太旧了
这时候,我们就可以考虑使用Gradle Wrapper了。这也是官方建议使用Gradle Wrapper的原因。实际上有了Gradle Wrapper之后,我们本地是可以不配置Gradle的,下载Gradle项目后,使用gade项目自带的wrapper操作也是可以的。
项目中的gradlew gradlew.cmd脚本用的就是wrapper中规定的gradle版本·参见源码
而我们上面提到的g红adle指令用的是本地gradle, 所以gradle指令和gradlew指令所使用的gradle版本有可能是不一样的
gradlew gadlew.cmd的使用方式与gradle使用方式完全一致,只不过把g红adle指令换成了gradlew指令。
当然我们也可在终端执行gradlew指令时,指定指定一些参数,来控制Wrapper的生成,比如依赖的版本等,如下:
参数 | 说明 |
---|---|
–gradle-version | 用于指定使用的gradle版本 |
–gradle-distribution-url | 用于指定下载gradle发行版url地址 |
执行gradle wrapper --gradle-version=7.4.2 --gradle-distribution-url=地址
下载别人的项目或者使用操作以前自己写的不同版本的gradle项目时:用Gradle wrapper,也即gradew
什么时候使用本地gradle?新建一个项目时:使用gradle指令即可。
在某种程度上,Groovy可以被视为Java的一种脚本化改良版,Groovy也是运行在JVM上,它可以很好地与Java代码
及其相关库进行交互操作。它是一种成熟的面向对象编程语言,既可以面向对象编程,又可以用作纯粹的脚本语言。
大多数有效的Java代码也可以转换为有效的Groovy代码,Groovy和Java语言的主要区别是:完成同样的任务所需的
Groovy代码比Java代码更少。其特点为:
> 功能强大,例如提供了动态类型转换、闭包和元编程(metaprogramming)支持
> 支持函数式编程,不需要main函数
> 默认导入常用的包
> 类不支持default作用域,且默认作用域为public。
> Groovy中基本类型也是对象,可以直接调用对象的方法。
> 支持DSL(Domain Specific Languages领域特定语言)和其它简洁的语法,让代码变得易于阅读和维护。
> Groovy是基于Java语言的,所以完全兼容Java语法,所以对于Java程序员学习成本较低。
详细了解参考官网. 官网地址http://www.groovy-lang.org/documentation.html
Task "task1" {
println "弟弟你真好"
doFirst {
println "弟弟身材真好"
}
doLast {
println "弟弟的腰 杀人的刀"
}
}
Task "Task2" {
doLast {
println "姐姐喜欢细狗"
}
}
Task2.dependsOn=['task1']
任务执行: gradle taskName, eg: gradle -i c 执行任务c
重复依赖的任务只执行一次
task task2(dependsOn:['task1']) {
group("abc") // 将任务task2添加到任务组abc
doLast {
println "task2 last"
}
}
//查看某个任务组下的任务列表
gradle tasks --group="abc" 查看任务组abc的任务
-h, --h 查看帮助信息
-v,–version 打印Gradle、Groovy、Ant、JVM和操作系统版本信息
-S, --full-stacktrace 打印出用户异常的堆栈跟踪 例如编译错误
-Dorg.gradle.daemon.debug=true 调试Gradle守护进程
-Dorg.gradle.debug=true 调试Gradle客户端(非daemon)进程
-Dorg.gradle.debug.port=port_number 指定启用调试时要监听的端口,默认是5005
gradle,properties.里面定义的属性是全局的,可以在各个模块的build.gradle里面直接引用,
当有一些数据我们传到git又不想给别人看的时候,就可以配置到gradle,properties,然后不传这个文件上去
也可以在项目中对一些属性进行统一配置,提高开发效率
–build-cache,-no-build-cache:尝试重用先前版本的输出。默认关闭(off)
–max-workers::设置Gradle可以使用的woker数。默认值是处理器数。
-parallel,.-no-parallel:并行执行项目。有关此选项的限制,请参阅并行项目执行。
默认设置为关闭(off)
-Dorg.gradle.logging.level=(quiet,warn,lifecycle,info,debug): 通过Gradle属性设置日志记录级别。
-q,一quiet:只能记录错误信息
-w,-warm:设置日志级别为warn
-i,-info:将日志级别设置为info
-d,一debug:登录调试模式(包括正常的堆栈跟踪)
-x:-x等价于:-exclude-.task: 常见gradle-x test clean build
-rerun-tasks: 强制执行任务,忽略up-to-date,常见gradle build-rerun-tasks
-continue:忽略前面失败的任务继续执行,而不是在遇到第一个失败时立即停止执行。每
个遇到的故障都将在构建结束时报告,常见:gradle build --continue.
gradle init --type pom将maven项目转换为gradle项目根目录执行
gradle [task Name] -执行自定义任务
Project中的task()方法,另一种是通过tasks对象的create或者register方法。
task('A', { // 任务名称,闭包都作为参数
println "taskA...."
})
task('B') { // 闭包作为最后一个参数可以直接从括号中拿出来
println "taskB..."
}
task C{ // groovy语法支持省略方法括号
println "taskC..."
}
def map = new HashMap();
map.put("action",{println "taskD..."}); //action属性可以设置为闭包
task(map,"D");
tasks.create("E"){ //使用tasks的create方法
println "taskE..."
}
tasks.register('f'){ // 注: register执行的是延迟创建,也即只有task被需要使用的时候才会被创建。
println "taskF..."
}
type: 基于一个存在的Tsk来创建,和我们类继承差不多。 默认值:DefaultTask
overwrite:是否替换存在的Task,这个和type配合起来用 默认值:false
dependsOn:用于配置任务的依赖 默认值:[]
action:添加到任务中的一个Action或者一个闭包。默认值:null
description:用于配置任务的描述。默认值:null
group:用于配置任务的分组。默认值:null
task("task3",description: "this is task3",group:"abc") {
doLast({
println "task3 ..."
})
}
task("task4"){
group("abc")
description("this is the task H")
}
前面我们定义的task都是DefaultTask类型的如果要完成某些具体的操作完全需要我们自己去编写gradle脚本,势必有些麻烦,那有没有一些现成的任务类型可以使用呢?有的,gradle官网给出了一些现成的任务类型帮助我们快速完成想要的任务,我们只需要在创建任务的时候,指定当前任务的类型即可,然后即可使用这种类型中的属性和API方法了。
常见任务类型 | 该类型任务的作用 |
---|---|
Delete | 删除文件或目录 |
Copy | 将文件复制到目标目录中。此任务还可以在复制时重命名和筛选文件 |
CreateStartScripts | 创建启动脚本 |
Exec | 执行命令进程 |
GenerateMavenPom | 生成Maven模块描述符POM文件 |
GradleBuild | 执行Gradle构建 |
Jar | 组装JAR归档文件 |
JavaCompile | 编译Java源文件 |
Javadoc | 为Java类生成HTML API文档 |
PublishToMavenRepository | 将MavenPublication发布到mavenartifactrepostal |
Tar | 组装TAR存档文件 |
Test | 执行Junit或TestNG测试 |
Upload | 将Configuration的构件上传到一组存储库 |
War | 组装War归档 |
Zip | 组装ZIP归档文件。默认是压缩ZIP的内容 |
提示1:gradle自带Task类型,参考官方文档
提示2:官方文档给出这些类型的时候,同时给出了案例代码,可以直接去上述官网的某个类型中观看
tasks.addRule(“rule desc”) {
String taskName -> task(taskName) {
println “the $taskName is not exist”
}
}
task hello {
doLast {
println "hello 粉丝们"
}
}
hello.onlyIf( !project.hasProperty('fensi'))
//没有这个属性 就会执行这个hello任务
> gradlew.bat hello
> hello 粉丝粉
> gradlew.bat hello -Pfensi //-P在根项目下添加属性
defaultTasks 'myClean', 'myRun'
tasks.register('myClean') {
doLast {
println 'Default cleaning!'
}
}
tasks.register('myRun') {
doLast {
println 'Default Running!'
}
}
tasks.register('other') {
doLast {
println "I'm not a default task!"
}
}
似乎没有起作用,可能与版本有关系。
// 使用本地文件的操作方式:相对路径
def file = file('D:/yuan.txt')
//file.createNewFile();
//file.write("spring source successfully")
//file.delete()
def fileCollection = files('src/text1.txt', 'src/tt.xml')
def fileSet = fileCollection as Set
def lists = fileCollection as List
def ff = fileCollection + lists
fileCollection.forEach { item -> println item.getName() }
Set<File> aa = fileCollection.files
// 文件树
def fileTree = fileTree('src/main')
fileTree.exclude("**/**.java").forEach { item -> println item }
//文件拷贝
task copyTask(type:Copy){
from 'src/main/resources'
into 'build/config'
}
// 文件复制
// 方式一:自定义任务
// 方式二: Project的copy方法
通常一个项目会有很多的Jar包,我们希望把项目打包成一个WAR,ZIP或TAR包进行发布,这时我们就可以使用
Zip,Tar,Jar,War和Ear任务来实现,r不过它们的用法都一样,所以在这里我只介绍Zip任务的示例。首先,创建
一个Z即压缩文件,并指定压缩文件名称,如下代码所示:
/**
*依赖方式:
* 本地依赖 依赖本地的某个jar包,具体通过文件集合 文件树的方式指定
* 项目依赖:依赖某个project
* 直接依赖:依赖的类型、依赖的组名、依赖的名称、依赖的版本号
*/
dependencies {
// 本地依赖-文件集合/文件树
implementation files('lib/mysql.jar','lib/log4j.jar')
// 项目依赖
implementation project(":spring-jdbc")
// 直接依赖
implementation 'mysql:mysql-connector-java:8.0.23'
// 完整写法
implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.33'
}
api | implement | |
---|---|---|
编译时 | 能进行依赖传递,底层变,全部都要变,编译速度慢 | 不能进行依赖传递,底层变,不用全部都要变,编译速度快 |
运行时 | 运行时会加载,所有模块的class都要被加载 | 运行时会加载,所有模块的class都要被加载 |
应用场景 | 适用于多模块依赖,避免重复依赖模块 | 多数情况下使用implementation |
依赖冲突是指"在编译过程中,如果存在某个依赖的多个版本,构建系统应该选择哪个进行构建的问题",如下所示:
dependencies {
testImplementation 'org.junit jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org junit jupiter:junit-jupiter-engine:5.s.1'
implementation('org.hibernate:hibernate-core:3.6.s.Final) {
//排除某一个库(s1f)依赖:如下三种写法都行
exclude group:'org.slftj
exclude module:'slftj-api'
exclude group:'org.slftj,module:'slftj-api
}
//排除之后,使用手动的引入即可
implementation 'org.slftj:slftj-api:1.4.0'
}
// 还有一种方式就是:
transitive(false)
// 强制使用某个版本
implementation ('org.slf4j:slf4j-api:1.4.0'){
version{
strictly("1.4.0")
}
或者
implementation ('org.slf4j:slf4j-api:1.4.0!!')
如果遇到冲突报错,否则默认采用最新的版本解决冲突
//下面我们配置,当Gradle构建遇到依赖冲突时,就立即构建失败
configurations.all() {
Configuration configuration ->
//当遇到版本冲突时直接构建失败
configuration.resolutionStrategy.failonVersionConflict()
}
简单的说,通过应用插件我们可以:
1. 促进代码重用、减少功能类似代码编写、提高工作效率
2. 促进项目更高程度的模块化、自动化、便捷化
3. 可插拔的扩展项目的功能
在项目构建过程中做很多事情,把插件应用到项目中,通常可以完成: