暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Gradle进阶

原创 我为啥没洁癖 2023-05-31
671

四、项目结构管理

4.1 用户目录

用户目录就是运行中的gradle项目依赖文件的存储位置,类似maven的本地仓库。用户目录位置:${user_home}/.gradle

目录结构

├── caches #全局缓存 │ ├── 4.8 #特定版本的缓存 │ ├── 4.9 #特定版本的缓存 │ ├── ⋮ │ ├── jars-3 #共享缓存,依赖包 │ └── modules-2 #共享缓存,依赖包 ├── daemon #gradle daemon的注册表和日志 │ ├── ⋮ │ ├── 4.8 │ └── 4.9 ├── init.d #全局初始化脚本 │ └── my-setup.gradle ├── jdks #toolchain support下载的jdk │ ├── ⋮ │ └── jdk-14.0.2+12 ├── wrapper │ └── dists #gradle warrper下载的文件 │ ├── ⋮ │ ├── gradle-4.8-bin │ ├── gradle-4.9-all │ └── gradle-4.9-bin └── gradle.properties #全局gradle配置
复制

缓存清理

Gradle会周期性的自动清理缓存。默认情况下,Gradle daemon线程停止后就会执行清理过程。如果使用了--no-daemon参数,清理过程在build完成后会显示在前台。

默认清理策略,每24小时执行一次

  1. caches下的特定版本目录会被检测是否被使用,如果没被使用,稳定版本30天被删除,快照版本7天被删除。
  2. 共享缓存也会被检测,如果没有特定版本的缓存使用对应的共享缓存就会被删除。
  3. wrapper/dists/取决于版本缓存和/cache/${version}目录是否一致,没用到的会被删除。

缓存执行频率

  • DEFAULT:默认,24小时一次
  • DISABLED:不执行。明确时间点清理时有用。
  • ALWAYS:每次执行build操作完成后执行。影响性能。

配置策略,${user_home}/.gradle/init.d/cache-settings.gradle文件

beforeSettings { settings -> settings.caches { //默认30天 releasedWrappers.removeUnusedEntriesAfterDays = 45 //默认7天 snapshotWrappers.removeUnusedEntriesAfterDays = 10 //默认30天 downloadedResources.removeUnusedEntriesAfterDays = 45 //默认7天 createdResources.removeUnusedEntriesAfterDays = 10 //缓存清理执行策略 cleanup = Cleanup.DISABLED } }
复制

4.2 项目目录

Java项目的目录结构。

目录结构

├── .gradle #项目特定的gradle缓存 │ ├── 4.8 #特定版本缓存 │ ├── 4.9 │ └── ⋮ ├── build #构建输出目录,编译的class文件和打包的jar包 ├── gradle #项目的Gradle Wrapper │ └── wrapper ├── gradle.properties #项目的gradle配置 ├── gradlew #执行gradle Wrapper命令的脚本,sh ├── gradlew.bat #执行gradle Wrapper命令的脚本,bat ├── settings.gradle or settings.gradle.kts #多项目配置项目列表 ├── subproject-one #子项目1 | └── build.gradle or build.gradle.kts #子项目1的gradle构建脚本,包含项目的配置信息,每个项目都有一个 ├── subproject-two | └── build.gradle or build.gradle.kts └── ⋮
复制

4.3 配置文件定义

添加warrper镜像

编辑gradle-wrapper.properties文件

distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists #使用镜像,不然zip包下载巨慢 distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists
复制

插件镜像配置

全局配置,在用户目录下的 .gradle/ 文件夹下创建文件 init.gradle (这个文件默认是没有创建的,需手动创建)。

如果配置了GRADLE_HOME,就放在GRADLE_HOME的init.d目录下面。

settingsEvaluated { settings -> settings.pluginManagement { repositories { maven { url "https://maven.aliyun.com/repository/gradle-plugin" } maven { url "https://maven.aliyun.com/repository/spring-plugin" } gradlePluginPortal() } } }
复制

项目配置,在项目的根目录的settings.gradle 文件中第一行加入,注意这配置必须要放在开头

pluginManagement { //插件镜像 repositories { maven { url "https://maven.aliyun.com/repository/gradle-plugin" } maven { url "https://maven.aliyun.com/repository/spring-plugin" } gradlePluginPortal() } }
复制

依赖镜像配置

全局配置,用户根目录下/.gradle/init.gradle。如果配置了GRADLE_HOME,就放在GRADLE_HOME的init.d目录下面。

buildscript { repositories { maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/central' } maven { url 'https://maven.aliyun.com/repository/public' } } allprojects { repositories { maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/central' } maven { url 'https://maven.aliyun.com/repository/public' } } } }
复制

项目级配置,项目根路径/build.gradle

buildscript { // 配置变量 ext { springBootVersion = '2.7.11' } // 插件仓库 repositories { maven { url "https://maven.aliyun.com/repository/gradle-plugin" } maven { url "https://maven.aliyun.com/repository/spring-plugin" } gradlePluginPortal() } // 应用插件需要的依赖包 dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } //依赖镜像 repositories { maven { url 'https://maven.aliyun.com/repository/central' } maven { url 'https://maven.aliyun.com/repository/public' } }
复制

Gradle控制台乱码

idea里面配置:help》edit custom vm options

#配置文件末尾加上这句后重启idea -Dfile.encoding=UTF-8
复制

项目目录指定

rootProject.name = '' include('app') project(':app').projectDir = file('../app') project(':app').buildFileName = 'build.gradle'
复制

五、配置编写

5.1 生命周期

整个构建的生命周期围绕task展开,task和task之间构成一个有向无环图。用户可以编写groovy脚本自己任意构建自定义的构建流程。Java插件提供了默认的生命周期,如下图:

image-20230530122612136

5.2 构建阶段

gradle的构建可以分为三个阶段:初始化、配置、执行。

初始化

初始化阶段主要是读取settings.gradle配置,初始化需要构建的project实例。

  • 读取settings.gradle配置,如果settings.gradle不存在,读取settings.gradle(.kts),如果也不存在就以单一项目进行build。
  • 根据settings.gradle的配置信息决定构建哪部分项目,如果是多project就按多project。settings.gradle不存在按单一project处理。
  • 为每个项目创建Project实例。每个项目都可以由子模块;除了root模块,所有模块都有一个父模块。

配置

在配置阶段,处理每个project实例的build.gradle配置,并生成任务执行方案。

  • 获取每个project的build.gradle配置
  • 生成任务执行方案

配置阶段的两个生命周期回调:beforeProject和afterProject

gradle.beforeProject { project -> project.ext.set("hasTests", false) } gradle.afterProject { project -> if (project.ext.has("hasTests") && project.ext.get("hasTests") as Boolean) { def projectString = project.toString() println "Adding test task to $projectString" project.task('test') { doLast { println "Running tests for $projectString" } } } }
复制

执行

执行阶段,gradle根据配置阶段生成的任务执行方案来执行任务

  • 按照任务执行方案顺序执行任务

    执行任务就是一个build过程,包含:下载依赖、编译源码、读取输入、输出

执行阶段的两个生命周期回调:beforeTask和afterTask

gradle.taskGraph.beforeTask { Task task -> println "executing $task ..." } gradle.taskGraph.afterTask { Task task, TaskState state -> if (state.failure) { println "FAILED" } else { println "done" } }
复制

5.3 声明变量

本地变量

本地变量只能在声明的scope范围使用

def dest = 'dest' tasks.register('copy', Copy) { from 'source' into dest }
复制

提取属性

使用ext来提取属性,一次定义多次使用。作用域更广泛,子模块可以直接访问父模块定义的ext属性。

父模块的build.gradle中定义

ext { springVersion = "2.7.11" }
复制

子模块的build.gradle中使用

dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test:${springVersion}' implementation('org.springframework.boot:spring-boot-starter-web:${springVersion}') }
复制

5.4 task声明

先声明名称为hello的task

//注册hello的task tasks.register('hello') { doLast { println 'Hello world!' } }
复制
#执行hello任务 gradle -q hello
复制

任务依赖

后声明的intro依赖于hello任务,执行intro之前会先执行hello,如果依赖的任务不存在就会是延迟依赖,一样可以正常执行。

//intro的task依赖hello tasks.register('intro') { dependsOn tasks.hello doLast { println "I'm Gradle" } }
复制

任务延迟依赖

任务声明时依赖其他的任务,但是被依赖的任务此时还不存在就会延迟依赖。

tasks.register('intro') { dependsOn tasks.hello doLast { println "I'm Gradle" } } tasks.register('hello') { doLast { println 'Hello world!' } }
复制

复杂任务

注意,groovy中单引号代表字符串,双引号才能占位

动态占位声明4个任务,分别是task0,task1,task2,task3,

4.times {counter ->{ tasks.register("task$counter"){ doLast { println "this is task $counter" } } }} //将任务名称当成变量直接引用 tasks.named('task0'){dependsOn('task1','task2','task3')}
复制
#执行task0任务 gradle -q task0
复制

5.5 插件机制

Gradle中大量功能都是通过插件提供。向编译Java代码的功能就是提供一个Java插件。插件主要分为两类:二进制插件和脚本插件,二进制插件可以包含在脚本插件内部。一般的插件开始是更简单的脚本形式,插件发展后更才成为二进制插件以便于测试和传播。

plugins模块引入

新版使用plugins代码块声明插件,比旧版的apply声明更具约束性

插件引入主要分为两个阶段:

  • relslove:解析插件的jar包版本并添加到脚本的classpath中,然后插件的功能就可以在构建脚本中使用。
  • apply:项目执行Plugin.apply(T)方法,apply方法幂等。

二进制插件可以通过插件id引入,id是一个唯一标识。也可以通过name引入。Gradle的核心插件有简称,如JavaPlugin的简称是java;其他的一些插件就需要完整id,例如com.github.foo.bar

有简称的核心插件引入

plugins { id 'java' }
复制

无简称的社区插件,必须完整id,使用ext引用版本变量

plugins { id 'org.springframework.boot' version "${springBootVersion}" }
复制

可以在父模块的build.gradle中声明插件的版本apply等,然后在子模块中引用。

父模块

plugins { id 'java' id 'org.springframework.boot' version "${springBootVersion}" apply false }
复制

子模块

plugins { id 'java' id 'org.springframework.boot' } apply plugin: 'io.spring.dependency-management'
复制

apply引入

id引入,简称全名均可

apply plugin: 'java'
复制

type引入,被gradle默认引入模块包含

apply plugin: JavaPlugin
复制

buildscript代码块引入

buildscript { ext { springBootVersion = '2.7.11' } repositories { maven { url "https://maven.aliyun.com/repository/gradle-plugin" } maven { url "https://maven.aliyun.com/repository/spring-plugin" } gradlePluginPortal() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'org.springframework.boot'
复制

引入脚本插件

apply from: 'other.gradle'
复制

5.6 多包互相导入

多包项目中,一个包引入另外一个包。

app和app2,在app2项目中引入app项目,引入后app2中直接使用app的代码

dependencies { implementation project(':app') }
复制

六、依赖处理

gradle支持各种发布路径,不仅包含Maven支持的各类仓库地址发布,而且包含自定义任意路径发布。

6.1 发布jar包

引入插件

plugins { id 'maven-publish' }
复制

定义AGV

Artifact名称取project.name属性,group和version也是project的对应属性。

group = 'org.xrj' version = '1.0.0'
复制

定义发布jar

这里定义了四种类型的Jar,分别是:

  1. app-1.0.0-plain.jar:class包,可以作为外部依赖使用。
  2. app-1.0.0-javadoc.jar:Java文档,内部是对应类的文档HTML文件。
  3. app-1.0.0-sources.jar:java包,内部是对应的Java源代码。
  4. app-1.0.0.jar:可执行Jar包,包含class包及其所有的依赖jar等。
java { withJavadocJar() //发布文档jar包,内部是javadoc的html文件,app-1.0.0-javadoc.jar withSourcesJar() //发布源码jar包,内部是源码java文件,app-1.0.0-sources.jar } publishing { publications { app(MavenPublication) { from components.java //发布归档jar包,内部是编译后class文件,app-1.0.0-plain.jar artifact bootJar //发布可执行boot包,内部包含所有依赖文件可java -jar运行,app-1.0.0.jar //版本映射策略,只发布bootJar时可以不用 versionMapping { usage('java-api') { fromResolutionOf('runtimeClasspath') } usage('java-runtime') { fromResolutionResult() } } } } }
复制

发布地址

发布地址和publications都在publishing代码块下。

每一个发布地址都会动态生成插件命令,这里定义了三类五种发布地址:

  1. mavenLocal:本地仓库,发布路径是$USER_HOME/.m2/repository
  2. maven:自定义仓库,url可以指定本地目录和http地址进行发布,此处的name必须指定唯一值。
    1. 项目路径repo:指定项目build目录下的repos目录
    2. 自定义路径repo:手动指定Maven的repo目录
    3. 远端repo:直接指定私有库的https地址,并设置用户名密码验证信息
  3. mavenCentral:中央仓库,发布到Maven的中央仓库。
publishing { repositories { //发布到本地仓库,默认是路径$USER_HOME/.m2/repository mavenLocal() //项目路径repo maven { name 'localBuildRepo' def releasesRepoUrl = layout.buildDirectory.dir('repos/releases') def snapshotsRepoUrl = layout.buildDirectory.dir('repos/snapshots') url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl } //自定义路径repo maven { name 'myRepo' url = layout.projectDirectory.dir('D:\\jenviorment\\apache-maven-3.8.6\\repo') } //远端repo maven { name 'huawei-cloud' def releasesRepoUrl = 'https://devrepo.devcloud.cn-north-4.huaweicloud.com/artgalaxy/cn-north-4_28e3db20d17644c1b392216ca50a185d_maven_1_0/' def snapshotsRepoUrl = 'https://devrepo.devcloud.cn-north-4.huaweicloud.com/artgalaxy/cn-north-4_28e3db20d17644c1b392216ca50a185d_maven_2_0/' url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl credentials{ username 'xxx' password 'xxx' } } //发布到maven中央仓库,需要申请中央仓库的账号 mavenCentral() } }
复制

发布命令

image-20230531123517091

6.2 依赖本地jar包

引入本地目录

repositories { //引入本地文件目录 flatDir(dirs: "lib") mavenCentral() }
复制

引入本地目录依赖

dependencies { // 依赖某个jar文件 implementation files('lib/xxx.jar') // 依赖libs目录下所有以.jar结尾的文件 implementation fileTree(dir: 'lib', includes: ['*.jar']) // 依赖libs目录下除了xxx.jar以外的所有以.jar结尾的文件 implementation fileTree(dir: 'lib', excludes: ['xxx.jar'], includes: ['*.jar']) }
复制

6.3 拆分打包SpringBoot

在对应项目底部增加下面的配置。然后执行bootJar进行打包即可。

拆分配置

// 将依赖包复制到lib目录 tasks.register('copyJar', Copy) { // 清除现有的lib目录 delete "$buildDir\\libs\\lib" //拷贝jar from configurations.runtimeClasspath into "$buildDir\\libs\\lib" from configurations.compileClasspath into "$buildDir\\libs\\lib" } // 拷贝配置文件 tasks.register('copyConfigFile', Copy) { // 清除现有的配置目录 delete "$buildDir\\libs\\config" from('src/main/resources') into 'build/libs/config' } //配置bootJar进行打包 bootJar { // 排除所有的jar excludes = ["*.jar"] // lib目录的清除和复制任务 dependsOn copyJar // 配置目录的清除和复制任务 dependsOn copyConfigFile // 指定依赖包的路径 manifest { attributes "Manifest-Version": 1.0, 'Class-Path': configurations.compileClasspath.files.collect { "lib/$it.name" }.join(' ') } }
复制

拆分结果

原本打包在一起的jar会被拆分成lib、配置、和代码jar三部分

image-20230531121909934

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

暂无图片
获得了351次点赞
暂无图片
内容获得346次评论
暂无图片
获得了697次收藏
TA的专栏
疑难杂症
收录3篇内容
minio
收录4篇内容
rocketmq
收录4篇内容
目录
  • 四、项目结构管理
    • 4.1 用户目录
      • 目录结构
      • 缓存清理
    • 4.2 项目目录
      • 目录结构
    • 4.3 配置文件定义
      • 添加warrper镜像
      • 插件镜像配置
      • 依赖镜像配置
      • Gradle控制台乱码
      • 项目目录指定
  • 五、配置编写
    • 5.1 生命周期
    • 5.2 构建阶段
      • 初始化
      • 配置
      • 执行
    • 5.3 声明变量
      • 本地变量
      • 提取属性
    • 5.4 task声明
      • 任务依赖
      • 任务延迟依赖
      • 复杂任务
    • 5.5 插件机制
      • plugins模块引入
      • apply引入
    • 5.6 多包互相导入
  • 六、依赖处理
    • 6.1 发布jar包
      • 引入插件
      • 定义AGV
      • 定义发布jar
      • 发布地址
      • 发布命令
    • 6.2 依赖本地jar包
      • 引入本地目录
      • 引入本地目录依赖
    • 6.3 拆分打包SpringBoot
      • 拆分配置
      • 拆分结果