当前位置:   article > 正文

Gradle开发手册-进阶篇_gradle 配置编写手册

gradle 配置编写手册

        在基础篇中了解了Gradle相关的知识同时通过一个例子实战了一下如何构建一个简单的Gradle-java应用。本章会详细讲解下gradle配置相关的详细内容。

  1. 基础篇:从概念以及广度上介绍下gradle的核心内容,并构建一个简单的java项目;
  2. 进阶篇:详细讲解Gradle的配置相关内容;
  3. 高级篇:讲述一些高级内容,比如多项目构建、自定义task等;
  4. 实战篇:构建几类常见的java应用,这些代码可以做为模板方便日后使用;
  5. FAQ篇:提供一些常用的命令和问题供查询;

        无论是使用本地安装,还是借助类似的Intellij idea工具构建Gradle应用,都会在本地系统中存在一个gradle的root目录,一般此目录存在于系统用户的根目录下,以笔者的macos系统为例,其根目录地址为:

/Users/liudong/.gradle 

        gradle的root目录存在的目的是为了方便资源共享和构建的管理,即gradle的root中的配置对所有本地的gradle应用都有效,同时每个本地的gradle应用都可以在build.gradle.kts进行配置覆盖root目录中的配置。在这个目录下两个文件夹需要关心一下:

  •  cachs\modules-2:所有依赖的jar包的缓存目录;
  • wrapper\dists:所有下载的不同版本的Gradle存放地址目录;

一、Gradle全局配置

        gradle的root目录中存在的配置我们暂时称做全局配置。在此处可以配置2个文件init.gradle和gradle.properties

  • init.gradle:对应的gradle init命令,主要配置一些公共资源,比如仓库、公共jar包等;
  • gradle.properties:与运行相关,可配置一些运行时参数和自定义的参数,比如jvm参数等;  

        当然了,Gradle的配置比较多,笔者只挑了一些开发时比较重要的总结下,详细的可以查看官方文档。

        .gradle目录下最初时没有gradle.properties和init.gradle这两个文件,需要手动添加,这两个文件就是全局配置文件。但建议每到一个公司就修改一个目录(习惯问题,可按个人习惯决定是否分开)

1、init.gradle初始化配置

        主要是配置jar文件下载时的镜像地址,需要在/Users/liudong/.gradle文件夹中新建一个init.gradle初始化脚本,这样一来,gradle下载镜像的时候就会使用这里配置的镜像源下载,速度会快很多,脚本文件内容如下: 

  1. allprojects {
  2. repositories {
  3. maven {
  4. url "https://maven.aliyun.com/repository/public"
  5. }
  6. maven {
  7. url "https://maven.aliyun.com/repository/jcenter"
  8. }
  9. maven {
  10. url "https://maven.aliyun.com/repository/spring"
  11. }
  12. maven {
  13. url "https://maven.aliyun.com/repository/spring-plugin"
  14. }
  15. maven {
  16. url "https://maven.aliyun.com/repository/gradle-plugin"
  17. }
  18. maven {
  19. url "https://maven.aliyun.com/repository/google"
  20. }
  21. maven {
  22. url "https://maven.aliyun.com/repository/grails-core"
  23. }
  24. maven {
  25. url "https://maven.aliyun.com/repository/apache-snapshots"
  26. }
  27. }
  28. }

2、gradle.properties运行时配置

        在/Users/liudong/.gradle文件夹中直接新建一个gradle.properties文件,创建内容不复杂,直接看代码即可,设置Gradle的JVM参数、代理和日志等信息,更多的设置可查看官网。

  1. #gradle运行时的jvm设置
  2. org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
  3. #gradle代理配置,按需配置即可
  4. systemProp.http.proxyHost=127.0.0.1
  5. systemProp.http.proxyPort=10800
  6. systemProp.https.proxyHost=127.0.0.1
  7. systemProp.https.proxyPort=10800
  8. systemProp.file.encoding=UTF-8
  9. org.gradle.warning.mode=all
  10. #gradle运行时的性能配置
  11. kotlin.incremental.useClasspathSnapshot = false
  12. kotlin.stdlib.default.dependency = false
  13. org.gradle.configuration-cache = true
  14. org.gradle.caching = true
  15. systemProp.org.gradle.unsafe.kotlin.assignment = true
  16. #日志输出级别,默认为Info,如果只输出错误日志则指定quiet,命令行执行时需要指定参数-q
  17. #./gradlew -q api:properties
  18. org.gradle.logging.level=(quiet,warn,lifecycle,info,debug)

其它几个常用的配置如下:

  • org.gradle.unsafe.configuration-cache = true:

          开启gradle缓存,加快构建速度

  • org.jetbrains.intellij.buildFeature.selfUpdateCheck=false:

         设置插件是否自动更新检查

  • org.jetbrains.intellij.buildFeature.buildSearchableOptions=false:

         禁止为插件生成索引信息

  • org.jetbrains.intellij.buildFeature.paidPluginSearchableOptionsWarning=false:

        如果插件为付费的,设置是否可搜索;

  • kotlin.incremental.useClasspathSnapshot=false:

       Kotlin 编译器抛出内存不足时的解决方法

  • kotlin.stdlib.default.dependency = false:

       如果Kotlin版本大于1.4设置成false,否则设置成true

  • runIde.autoReloadPlugins = true:

       修改插件后可重新运行build插件,这样就会自动更新了

以上配置都可以在项目中的gradle.properties和buide.gradlw.kts构建脚本中覆盖。

二、Project中Gradle配置

        我们以上一篇文章中通过Intellij idea创建的的项目(单模块)为例进行配置扩展。上一章中创建的项目结构如下图所示,详细文件说明就累述了,可查看基础篇中的描述:

         本节完整后的完整的项目结构会新增一个名为gradle.properties的项目配置文件。这个文件中的配置会自动被build.gradle.kts构建脚本引用,并通过编程的方式可以取得配置信息。一般来讲会配置与性能相关的参数,如缓存、jvm参数等,简单示例如下:

  1. #性能配置
  2. kotlin.incremental.useClasspathSnapshot = false
  3. kotlin.stdlib.default.dependency = false
  4. org.gradle.configuration-cache = true
  5. org.gradle.caching = true
  6. systemProp.org.gradle.unsafe.kotlin.assignment = true

        完善后的项目结构如下,只新增了gradle.properties文件,详细的属性取值方法会在后面讲解,此处可以先忽略内容或文件内容置空即可:

1、Gradle-Wrapper配置

        可以称Gradle Wrapper为Gradle包装器,是将Gradle再次包装。让所有的Gradle构建方法在 Gradle 包装器的帮助下运行。目的是可以让我们不需要在电脑中安装 Gradle 环境也可以运行 Gradle 项目。官方建议任何 Gradle 构建方法在 Gradle Wrapper帮助下运行,利于多人协同开发时环境的统一,在工程中会存在两个文件,其中gradle-wrapper.properties就是wrapper的配置文件。

  • gradle-wrapper.jar: 既然是 jar 包,那么它肯定是包含了 Gradle 运行时的逻辑代码;
  • gradle-wrapper.properties: 这个文件主要负责配置Gradle wrapper运行时的属性文件,声明具体使用哪个版本的 Gradle,详细配置如下:
  1. #Gradle根目录,默认根目录是/Users/userName/.gradle/;
  2. distributionBase=GRADLE_USER_HOME
  3. #distributionBase+distributionPath就是Gradle解包后的存放的具体目录
  4. distributionPath=wrapper/dists
  5. #Gradle项目中用到的Gradle版本,如果你使用IDEA的话推荐下载all版,这样可以分析源代码进而提供更加精确的gradle脚本支持
  6. distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
  7. #Gradle压缩包下载后存储父目录
  8. zipStoreBase=GRADLE_USER_HOME
  9. #zipStoreBase+zipStorePath就是 Gradle 压缩包的存放位置
  10. zipStorePath=wrapper/dists

        此文件中唯一需要更改的就是distributionUrl参数,这是用来指定gradle的版本,比如采用8.0版本(建议采用8.1.1版本)默认值是gradle-8.0-bin.zip,但建议把bin(只有编译后的文件)改成all(包含源码),这样有利于脚本debug。

2、gradle配置

        就是上面提到的用于提供运行时配置的gradle.properties文件,这个文件中可以配置两种类型的属性:1、运行时配置,因配置比较多,详细需要查看官网;2、自定义属性。此处只演示功能,暂时我们把内容配置如下:

  1. #运行时参数
  2. org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
  3. org.gradle.configuration-cache = true
  4. org.gradle.caching = true
  5. kotlin.incremental.useClasspathSnapshot = false
  6. kotlin.stdlib.default.dependency = false
  7. systemProp.org.gradle.unsafe.kotlin.assignment = true
  8. #自定义用户属性
  9. pluginSinceBuild = 221
  10. org.gradle.project.foo=bar
  11. #自定义系统属性
  12. systemProp.gradle.wrapperUser=我的用户

三、build构建脚本配置

        这个文件相当于maven的pom.xml配置文件,即gradle的所有行为全是在这个文件中定义的,可以采用Kotlin和groovy两种语言编写,本专题中笔者全部采用kotlin语言编写。主要的配置内容如下图所示:

1、获取属性

        在gradle中大概有以下几种属性的配置方式,如果在多个地方配置了同名的参数,则优先级从高到底如下:

  1. 命令行属性:在输入命令时通过-D附带参数,比如 $ gradle -DgradlePropertiesProp=commandLineValue--build-cache ;
  2. Gradle配置:root目录中gradle.properties文件中的配置;
  3. Project配置:项目中gradle..properties文件中的配置;
  4. 系统环境变量:比如window的环境变量和linux系统下的.bash_profile中的配置;

        建议采用第3种,因为在多人协作开发时这样有利于环境的统一,因为其它三种全依赖本地环境。

        另外每在plugins中添加一个id内容,就会在右侧插件UI上多出一个可点击的任务类型。

         属性也有不同的分类,不同种类的属性相对的也会有4种不同的属性getter接口,大体如下。

取得普通配置属性

         自定义属性和gradle相关的属性

  1. org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
  2. pluginSinceBuild = 221
  3. org.gradle.project.foo=bar

        提取API可以使用property和providers两种区别不大

  1. println(providers.gradleProperty("org.gradle.jvmargs").get())
  2. println(property("org.gradle.jvmargs"))
  3. println(providers.gradleProperty("pluginSinceBuild").get())
  4. println(property("org.gradle.project.foo"))

取得系统属性

        这种方式的属性也是自定义属性,但定义和取值的方式不同,这种是必须以systemProp开头的参数。

systemProp.gradle.wrapperUser=我的用户

        提取API,注意key会省略systemProp

println(System.getProperty("gradle.wrapperUser"))

取得系统环境变量

        这种就是读取本地系统的环境变量内容,不需要定义。

println(System.getenv("ENVIRONMENTAL"))

2、project基本配置

       以下所有小节的内容代码是增量添加的关系。需要手动拷贝到build.gradle.kts文件相应的位置上。

项目类型配置

        标识项目的类型,类型有很多,后面在实战章节会详细讲述,此处仅以发布为带有main.class的jar程序为例,其配置如下:

  1. plugins {
  2. id("application")
  3. }
  4. application {
  5. mainClass.set("org.korgs.Main")
  6. }

开发语言配置

        java

  1. plugins {
  2. id("java")
  3. }
  4. java {
  5. sourceCompatibility = JavaVersion.VERSION_17
  6. targetCompatibility = JavaVersion.VERSION_17
  7. }
  8. tasks {
  9. withType<JavaCompile> {
  10. sourceCompatibility = "17"
  11. targetCompatibility = "17"
  12. }
  13. }

        kotlin

  1. plugins {
  2. id("java")
  3. id("org.jetbrains.kotlin.jvm") version "1.8.21"
  4. }
  5. java {
  6. sourceCompatibility = JavaVersion.VERSION_17
  7. targetCompatibility = JavaVersion.VERSION_17
  8. }
  9. tasks {
  10. compileKotlin {
  11. kotlinOptions.jvmTarget = "17"
  12. }
  13. compileTestKotlin {
  14. kotlinOptions.jvmTarget = "17"
  15. }
  16. }

声明源码路径

  1. //本模块
  2. sourceSets {
  3. main {
  4. java {
  5. setSrcDirs(listOf("src"))
  6. }
  7. resources {
  8. setSrcDirs(listOf("src/resources"))
  9. }
  10. }
  11. test {
  12. java {
  13. setSrcDirs(listOf("test"))
  14. }
  15. resources {
  16. setSrcDirs(listOf("test/resources"))
  17. }
  18. }
  19. }
  20. //外部引用,不是太常用
  21. sourceSets {
  22. main {
  23. java {
  24. srcDir("thirdParty/src/main/java")
  25. }
  26. }
  27. }

项目坐标配置

  1. group = 'com.zd'
  2. version = '1.0-SNAPSHOT'

打包类型配置

        jar

  1. plugins {
  2. application
  3. }
  4. application {
  5. mainClass.set("org.korgs.Main")
  6. }

        war

  1. plugins {
  2. war
  3. }
  4. tasks.war {
  5. webAppDirectory.set(file("src/main/webapp"))
  6. from("src/rootContent") // adds a file-set to the root of the archive
  7. webInf { from("src/additionalWebInf") } // adds a file-set to the WEB-INF dir.
  8. classpath(fileTree("additionalLibs")) // adds a file-set to the WEB-INF/lib dir.
  9. classpath(moreLibs) // adds a configuration to the WEB-INF/lib dir.
  10. webXml = file("src/someWeb.xml") // copies a file to WEB-INF/web.xml
  11. }

        打一个胖包

        有两种方式,哪种都可以

  1. // 将依赖打进jar包中,生成的文件名gradleDemo-1.0-SNAPSHOT.jar
  2. tasks {
  3. jar.configure {
  4. duplicatesStrategy = org.gradle.api.file.DuplicatesStrategy.INCLUDE
  5. from(configurations.runtimeClasspath.get().filter { it.name.endsWith("jar")}.map { zipTree(it) })
  6. }
  7. }
  8. // 将依赖打进jar包中,生成的文件名gradleDemo-1.0-SNAPSHOT-uber.jar
  9. tasks.register<Jar>("uberJar") {
  10. archiveClassifier.set("uber")
  11. from(sourceSets.main.get().output)
  12. dependsOn(configurations.runtimeClasspath)
  13. from({
  14. configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
  15. })
  16. }

发布配置

  1. plugins {
  2. id 'maven-publish'
  3. }
  4. publishing {
  5. publications {
  6. myLibrary(MavenPublication) {
  7. from components.java
  8. }
  9. }
  10. repositories {
  11. maven {
  12. // default credentials for a nexus repository manager
  13. credentials {
  14. username 'admin'
  15. password 'xxxxx'
  16. }
  17. allowInsecureProtocol = true //允许http
  18. // 发布maven存储库的url
  19. url "http://localhost:8080/nexus/content/repositories/releases/"
  20. }
  21. }
  22. }

3、project依赖配置

 插件配置

        gradle插件类似于maven插件,plugins标签里的插件必须是gradle官方插件库(​​http://plugins.gradle.org​​​)里的,另外plugins块不能放在多项目配置块(allProjects, subProjects)里。<plugins>中添加一个id内容,就会在右侧插件UI上多出一个可点击的任务类型。

将插件应用于项目允许插件扩展项目的功能,它可以做如下事情:

  • 扩展 Gradle 模型(例如添加可配置的新 DSL 元素)
  • 根据约定配置项目(例如添加新任务或配置合理的默认值)
  • 应用特定配置(例如添加组织存储库或执行标准)

通过应用插件,而不是向项目构建脚本添加逻辑,我们可以获得很多好处,应用插件:

  • 促进重用并减少跨多个项目维护相似逻辑的开销
  • 允许更高程度的模块化,增强可理解性和组织性
  • 封装命令式逻辑并允许构建脚本尽可能具有声明性

  1. plugins {
  2. id 'org.springframework.boot' version '2.7.4'
  3. id 'java'
  4. }

        ps:因为java是核心插件,所以不用指定版本,而其它的插件比如org.springframework.boot是社区插件,必须指定版本。

仓库配置

         gradle仓库可以直接使用maven的仓库,但是gradle下载的jar包文件格式与maven不一样,所以不能和maven本地仓库共用,仓库的配置如下:

  1. repositories {
  2. mavenLocal() //本地仓库
  3. maven { url 'http://maven.aliyun.com/nexus/content/groups/public' } //外部仓库(阿里云)
  4. mavenCentral() // maven 中心仓库
  5. }

jar依赖配置

          gradle依赖写在<dependcies>代码块中,遵循​scope(gropId:artifactId:version)​格式。

  1. dependencies {
  2. testImplementation('junit:junit:4.13')
  3. implementation('org.projectlombok:lombok:1.18.26')
  4. implementation('mysql:mysql-connector-java:8.0.32')
  5. }

Scope说明:maven只有compile、provided、test、runtime,而gradle有以下几种scope:

  • implementation:默认的scope,会将指定的依赖添加到编译路径,并且会将该依赖打包到输出,但是这个依赖在编译时不能暴露给其他模块,例如如果我们的类库包含了gson,那么其他人使用我们的类库时,编译时不会出现gson的依赖。
  • api:api关键字是由java-library提供,若要使用,请在plugins中添加:​​id 'java-library'​​== (在旧版本中作用与compile相同,新版本移除了compile)使用api配置的依赖会将对应的依赖添加到编译路径,并将依赖打包输出,但是这个依赖是可以传递的,比如模块A依赖模块B,B依赖库C,模块B在编译时能够访问到库C,但是与implemetation不同的是,在模块A中库C也是可以访问的。
  • compileOnly:compileOnly修饰的依赖会添加到编译路径中,但是不会被打包,因此只能在编译时访问,且compileOnly修饰的依赖不会传递。
  • runtimeOnly:这个与compileOnly相反,它修饰的依赖不会添加到编译路径中,但是能被打包,在运行时使用。和Maven的provided比较接近。
  • annotationProcessor:用于注解处理器的依赖配置。
  • testImplementation:这种依赖在测试编译时和运行时可见,类似于Maven的test作用域。
  • testCompileOnly和testRuntimeOnly:这两种类似于compileOnly和runtimeOnly,但是作用于测试编译时和运行时。
  • classpath:见上一段,classpath并不能在buildscript外的dependcies中使用

jar包依赖排除配置

        开发过程中,或多或少都会遇到 jar 包冲突的问题,有时候两个 jar 包不同,但是里面有两个类的包名路径是一摸一样的。这样我们就需要排除掉某个包中的重复的类,这时候就需要用的 exclude 命令,如下例子:

        排除关联依赖

  1. compileOnly('org.hibernate:hibernate:3.1') {
  2. exclude module: 'cglib' //通过artifact name来排除出
  3. exclude group: 'org.jmock' //通过group name来排除
  4. }

        排除环境依赖

  1. configurations {
  2. runtime.exclude group: "org.slf4j", module: "slf4j-log4j12"
  3. compile.exclude group: "org.slf4j", module: "slf4j-log4j12"
  4. }

        全局排除依赖

  1. configurations.all {
  2. exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
  3. }

buildscript配置

        buildscript中的声明是gradle脚本自身需要使用的资源。可以声明的资源包括依赖项、第三方插件、maven仓库地址等。而在build.gradle.kts文件中直接声明的依赖项、仓库地址等信息是项目自身需要的资源。gradle在执行脚本时,会优先执行buildscript代码块中的内容,然后才会执行剩余的build脚本。

        buildscript代码块中的repositories和dependencies的使用方式与直接在build.gradle文件中的使用方式几乎完全一样。唯一不同之处是在buildscript代码块中你可以对dependencies使用classpath声明。该classpath声明说明了在执行其余的build脚本时,class loader可以使用这些你提供的依赖项。这也正是我们使用buildscript代码块的目的。某种意义上来说,classpath 声明的依赖,不会编译到最终的jar包里面。

  1. import org.apache.commons.codec.binary.Base64
  2. buildscript {
  3. ext {
  4. springBootVersion = "2.3.3.RELEASE"
  5. }
  6. repositories {
  7. mavenCentral()
  8. }
  9. dependencies {
  10. "classpath"(group = "commons-codec", name = "commons-codec", version = "1.2")
  11. }
  12. }
  13. tasks.register("encode") {
  14. doLast {
  15. val encodedString = Base64().encode("hello world\n".toByteArray())
  16. println(String(encodedString))
  17. }
  18. }

        注意,上面代码中的ext代码块,ext代码块是提供给用户自定义属性用的,一般用来定义版本,实现版本的集中管理

四、java-plug插件任务详解

        引入插件

  1. plugins {
  2. java
  3. }

1、常用任务

compileJava— JavaCompile

        Depends on:所有有助于编译类路径的任务,包括jar来自通过项目依赖项位于类路径上的项目的任务,使用 JDK 编译器编译生产 Java 源文件。

processResourcesProcessResources

        将生产资源复制到生产资源目录中。

classes

        取决于compileJavaprocessResources,这是一个仅依赖于其他任务的聚合任务。其他插件可能会附加额外的编译任务。

compileTestJava— JavaCompile

        取决于:classes以及对测试编​​译类路径有贡献的所有任务,使用 JDK 编译器编译测试 Java 源文件。

processTestResourcescopy

        将测试资源复制到测试资源目录中。

testClasses

        取决于compileTestJavaprocessTestResources,这是一个仅依赖于其他任务的聚合任务。其他插件可能会附加额外的测试编译任务。

jarjar

        取决于classes,根据附加到main源集的类和资源组装生产 JAR 文件。

javadoc— Javadoc

        取决于classes,使用 Javadoc 为生产 Java 源代码生成 API 文档。

testtest

        取决于:testClasses以及生成测试运行时类路径的所有任务,使用 JUnit 或 TestNG 运行单元测试。

cleanclean

        删除项目构建目录。

cleanTaskNameclean

        删除指定任务创建的文件。例如,cleanJar将删除任务创建的 JAR 文件jarcleanTest将删除任务创建的测试结果test

2、源码处理相关

compileSourceSetJava— JavaCompile

        取决于:对源集的编译类路径有贡献的所有任务使用 JDK 编译器编译给定源集的 Java 源文件。

processSourceSetResourcescopy

        将给定源集的资源复制到资源目录中。

sourceSetClassestask

        取决于:,compileSourceSetJavaprocessSourceSetResources准备给定源集的类和资源以进行打包和执行。一些插件可能会为源集添加额外的编译任务。

3、生命周期相关

assemble

        取决于jar,以及创建附加到archives配置的工件的所有其他任务聚合项目中所有档案的聚合任务。此任务由 Base Plugin 添加。

check

        取决于test,执行验证任务的聚合任务,例如运行测试。一些插件将自己的验证任务添加到checkTest如果您希望它们在完整构建中执行,您还应该将任何自定义任务附加到此生命周期任务。此任务由 Base Plugin 添加。

build

        取决于checkassemble。聚合执行项目完整构建的任务。此任务由 Base Plugin 添加。

buildNeeded

        Depends on :build和配置buildNeeded中依赖的所有项目中的任务testRuntimeClasspath执行项目及其依赖的所有项目的完整构建。

buildDependents

        Depends on :build和所有项目中的任务,这些项目在其配置buildDependents中具有该项目的依赖项testRuntimeClasspath执行项目和依赖它的所有项目的完整构建。

buildConfigName— taskRule

        取决于:生成附加到命名的工件的所有任务 -  ConfigName - 配置。为指定配置组装工件。此规则由 Base Plugin 添加。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号