第一章:Gradle 日志信息

1.1 概述

  • 在进行项目开发的过程之中,所有重要的数据内容一般都需要通过日志的形式进行输出,既然 Gradle 是以 Groovy 语言编写的可编程的构建工具,那么在进行每一个任务处理的时候也可以进行日志的配置,同时在 Gradle 内部直接提供有各种日志的组件。

1.2 日志输出

  • 所有的日志都是有日志等级的: | 等级 | 描述 | | —- | —- | | ERROR | 错误消息 | | QUIET | 重要消息信息 | | WARN | 警告信息 | | LIFECYCLE | 进度消息信息 | | INFO | 信息消息 | | DEBUG | 调试信息 |
  • 使用不同的日志等级实现日志信息的打印,修改 build.gradle 文件:
  1. task helloTask {
  2. doFirst {
  3. logger.log(LogLevel.ERROR,'【ERROR】这是一个 ERROR 级别日志信息')
  4. logger.quiet('【QUIET】这是一个 QUIET 级别日志信息')
  5. logger.info('【INFO】这是一个 INFO 级别日志信息')
  6. logger.log(LogLevel.WARN,'【WARN】这是一个 WARN 级别日志信息')
  7. logger.debug('【DEBUG】这是一个 DEBUG 级别日志信息')
  8. logger.lifecycle('【LIFE_CYCLE】这是一个 LIFE_CYCLE 级别日志信息')
  9. }
  10. }
  • 程序执行命令:
  1. gradle helloTask
  • 程序执行结果:
  1. 14:20:01: 正在执行 'helloTask'
  2. > Task :helloTask
  3. QUIET】这是一个 QUIET 级别日志信息
  4. WARN】这是一个 WARN 级别日志信息
  5. LIFE_CYCLE】这是一个 LIFE_CYCLE 级别日志信息
  6. BUILD SUCCESSFUL in 58ms
  7. 1 actionable task: 1 executed
  8. ERROR】这是一个 ERROR 级别日志信息
  9. 14:20:02: 执行完成 'helloTask'
  • 这个时候日志的确是提供了,但是默认情况下执行的任务并不会触发所有的日志输出操作,如果要想获得指定类型的日志信息,那么就需要在任务执行的时候进行配置了。

1.3 日志控制

  • 对于不同级别的日志,需要通过任务执行的时候配置不同的日志等级才可以实现输出,对于日志等级有如下的几个配置项: | 选项 | 输出日志级别 | | —- | —- | | 没有日志选项 | LIFECYCLE 或更高 | | -q 或 —quiet | QUIET 或更高 | | -w 或 —warn | WARN 或更高 | | -i 或 —info | INFO 或更高 | | -d 或 —debug | DEBUG 或更高 |
  • 对于所有的日志,肯定要设置输出级别才能准确获取相应的日志信息。

  • 示例:使用 debug 日志范围

  • 程序执行命令:
  1. gradle helloTask --debug
  • 程序执行结果:
  1. 2021-12-27T14:26:58.616+0800 [QUIET] [org.gradle.api.Task] QUIET】这是一个 QUIET 级别日志信息
  2. 2021-12-27T14:26:58.616+0800 [INFO] [org.gradle.api.Task] INFO】这是一个 INFO 级别日志信息
  3. 2021-12-27T14:26:58.616+0800 [WARN] [org.gradle.api.Task] WARN】这是一个 WARN 级别日志信息
  4. 2021-12-27T14:26:58.616+0800 [DEBUG] [org.gradle.api.Task] DEBUG】这是一个 DEBUG 级别日志信息
  5. 2021-12-27T14:26:58.616+0800 [LIFECYCLE] [org.gradle.api.Task] LIFE_CYCLE】这是一个 LIFE_CYCLE 级别日志信息

第二章:Gradle 项目源代码打包

2.1 概述

  • 对于任何一个项目来说,除了需要将核心的功能程序(编译后的)进行打包处理之外,实际上还需要考虑的就是开源项目中的源代码的打包操作,对于源代码的打包操作,需要单独配置有一个 Gradle 任务才可以实现。

2.2 源代码任务

  • 如果要想进行源代码的打包,那么需要定义个新的任务,但是这个任务需要继承一个 jar 已有的任务,修改 build.gradle 文件:
  1. // 最终生成的 jar 文件名称:baseName-version-classifier.extension
  2. task sourceJar(type: Jar) { // 定义一个源代码的打包任务
  3. archiveBaseName.set 'gradle-01' // 生成 jar 文件的名称
  4. archiveVersion.set '1.0.0' // 定义项目打包版本
  5. archiveClassifier.set 'sources' // 文件的分类
  6. from sourceSets.main.allSource // 所有源代码的读取路径
  7. exclude(['**/*.xml', '**/*.properties']) // 排除配置文件,可选
  8. destinationDirectory.file("$buildDir/source-jar") // 目标存储路径
  9. manifest {
  10. attributes 'packageName': 'com.github.fairy.era',
  11. 'Built-By': '许大仙',
  12. 'Built-date': new Date().format('yyyy-MM-dd HH:mm:ss'),
  13. 'Manifest-Version': archiveVersion
  14. }
  15. }
  • 完整的 build.gradle 文件:
  1. plugins {
  2. id 'java' // 配置的是一个 Java 插件(Java 项目)
  3. id 'java-library'
  4. }
  5. ext {
  6. jdkVersion = JavaVersion.VERSION_1_8 // 传统的 JDK 版本都是需要自己编写字符串的,而 Gradle 中提供了这样的操作
  7. }
  8. apply from: 'dependencies.gradle' // 引入所有的依赖文件
  9. configurations { // 进行依赖的配置
  10. implementation {
  11. canBeConsumed = true
  12. canBeResolved = true
  13. }
  14. }
  15. group 'com.github.fairy.era' // 组织名称
  16. version '1.0' // 项目版本
  17. // 定义一个公共的变量描述当前使用的 JDK 版本
  18. sourceCompatibility = jdkVersion
  19. targetCompatibility = jdkVersion
  20. repositories { // 仓库配置
  21. mavenCentral()
  22. }
  23. dependencies { // 依赖管理
  24. // compile gradleApi()
  25. /* junit 5 */
  26. testImplementation( // 如果有多个依赖,使用 , 隔开
  27. libraries.'junit-jupiter'
  28. )
  29. /* druid */
  30. implementation( // 如果有多个依赖,使用 , 隔开
  31. libraries.'druid'
  32. )
  33. }
  34. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  35. options.encoding = "UTF-8"
  36. }
  37. def mainClassName = 'com.github.fairy.era.GradleMain' // 程序的主类名称
  38. jar {
  39. archivesBaseName = 'gradle' // 生成的 jar 文件名称,如果不写此名称则使用项目名称
  40. manifestContentCharset = 'UTF-8' // 设置整个文件的编码
  41. metadataCharset = 'UTF-8' // 元数据设置编码
  42. manifest {
  43. attributes 'Manifest-Version': getArchiveVersion().getOrNull(), // 程序版本号
  44. 'Main-Class': "${mainClassName}",// 程序主类名称
  45. 'Implementation-Title': 'hello-gradle',// 程序主类名称
  46. 'Implementation-Version': archiveVersion // 版本编号
  47. }
  48. into('lib') { // 将程序锁需要的第三方组件包配置到 lib 目录之中
  49. from configurations.compileClasspath
  50. }
  51. }
  52. test { // 进行测试任务的配置
  53. useJUnitPlatform() // 使用 Junit 平台
  54. }
  55. sourceSets { // 建立源代码的目录集合
  56. main {
  57. java {
  58. srcDirs = ['src/main/java']
  59. }
  60. resources {
  61. srcDirs = ['src/main/resources', 'src/main/config']
  62. }
  63. }
  64. }
  65. // 最终生成的 jar 文件名称:baseName-version-classifier.extension
  66. task sourceJar(type: Jar) { // 定义一个源代码的打包任务
  67. archiveBaseName.set 'gradle-01' // 生成 jar 文件的名称
  68. archiveVersion.set '1.0.0' // 定义项目打包版本
  69. archiveClassifier.set 'sources' // 文件的分类
  70. from sourceSets.main.allSource // 所有源代码的读取路径
  71. exclude(['**/*.xml', '**/*.properties']) // 排除配置文件,可选
  72. destinationDirectory.file("$buildDir/source-jar") // 目标存储路径
  73. manifest {
  74. attributes 'packageName': 'com.github.fairy.era',
  75. 'Built-By': '许大仙',
  76. 'Built-date': new Date().format('yyyy-MM-dd HH:mm:ss'),
  77. 'Manifest-Version': archiveVersion
  78. }
  79. }

2.3 打包处理

  • 既然此时已经明确的定义一个打包任务,那么就可以直接通过此任务的执行来实现源代码包的生成。
  • 程序执行命令:
  1. gradle sourceJar
  • 程序执行结果:

1.png

2.4 打包时机

  • 当前的操作虽然可以编写任务实现源代码的打包处理操作,但是有一个问题:通常是在程序最终编译的时候才进行打包处理,如果按照以上的方式单独定义一个新的任务,则意味着需要在整个程序之中单独配置任务,能够将这些任务合并在一起?
  • 修改 build.gradle 文件:
  1. task sourceJar(type: Jar,dependsOn: classes) { // 定义一个源代码的打包任务,并依赖于 classes 这种 Gradle 内置的任务
  2. archiveClassifier.set 'sources' // 文件的分类
  3. from sourceSets.main.allSource // 所有源代码的读取路径
  4. }

2.5 命令整合

  • 以上的任务仅仅是对已有的任务做了一个扩展,但是需要注意的是,毕竟现在的需求是将整个源代码的操作放在 build 之中,所以还需要进行一个额外的配置,修改 build.gradle 文件:
  1. // 最终生成的 jar 文件名称:baseName-version-classifier.extension
  2. task sourceJar(type: Jar,dependsOn: classes) { // 定义一个源代码的打包任务,并依赖于 classes 这种 Gradle 内置的任务
  3. archiveClassifier.set 'sources' // 文件的分类
  4. from sourceSets.main.allSource // 所有源代码的读取路径
  5. }
  6. artifacts { // 最终的打包操作任务
  7. archives sourceJar
  8. }
  • 完整的 build.gradle 文件:
  1. plugins {
  2. id 'java' // 配置的是一个 Java 插件(Java 项目)
  3. id 'java-library'
  4. }
  5. ext {
  6. jdkVersion = JavaVersion.VERSION_1_8 // 传统的 JDK 版本都是需要自己编写字符串的,而 Gradle 中提供了这样的操作
  7. }
  8. apply from: 'dependencies.gradle' // 引入所有的依赖文件
  9. configurations { // 进行依赖的配置
  10. implementation {
  11. canBeConsumed = true
  12. canBeResolved = true
  13. }
  14. }
  15. group 'com.github.fairy.era' // 组织名称
  16. version '1.0' // 项目版本
  17. // 定义一个公共的变量描述当前使用的 JDK 版本
  18. sourceCompatibility = jdkVersion
  19. targetCompatibility = jdkVersion
  20. repositories { // 仓库配置
  21. mavenCentral()
  22. }
  23. dependencies { // 依赖管理
  24. // compile gradleApi()
  25. /* junit 5 */
  26. testImplementation( // 如果有多个依赖,使用 , 隔开
  27. libraries.'junit-jupiter'
  28. )
  29. /* druid */
  30. implementation( // 如果有多个依赖,使用 , 隔开
  31. libraries.'druid'
  32. )
  33. }
  34. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  35. options.encoding = "UTF-8"
  36. }
  37. def mainClassName = 'com.github.fairy.era.GradleMain' // 程序的主类名称
  38. jar {
  39. archivesBaseName = 'gradle' // 生成的 jar 文件名称,如果不写此名称则使用项目名称
  40. manifestContentCharset = 'UTF-8' // 设置整个文件的编码
  41. metadataCharset = 'UTF-8' // 元数据设置编码
  42. manifest {
  43. attributes 'Manifest-Version': getArchiveVersion().getOrNull(), // 程序版本号
  44. 'Main-Class': "${mainClassName}",// 程序主类名称
  45. 'Implementation-Title': 'hello-gradle',// 程序主类名称
  46. 'Implementation-Version': archiveVersion // 版本编号
  47. }
  48. into('lib') { // 将程序锁需要的第三方组件包配置到 lib 目录之中
  49. from configurations.compileClasspath
  50. }
  51. }
  52. test { // 进行测试任务的配置
  53. useJUnitPlatform() // 使用 Junit 平台
  54. }
  55. sourceSets { // 建立源代码的目录集合
  56. main {
  57. java {
  58. srcDirs = ['src/main/java']
  59. }
  60. resources {
  61. srcDirs = ['src/main/resources', 'src/main/config']
  62. }
  63. }
  64. }
  65. // 最终生成的 jar 文件名称:baseName-version-classifier.extension
  66. task sourceJar(type: Jar,dependsOn: classes) { // 定义一个源代码的打包任务,并依赖于 classes 这种 Gradle 内置的任务
  67. archiveClassifier.set 'sources' // 文件的分类
  68. from sourceSets.main.allSource // 所有源代码的读取路径
  69. }
  70. artifacts { // 最终的打包操作任务
  71. archives sourceJar
  72. }
  • 程序执行命令:
  1. gradle clean build -x test
  • 程序执行结果:

2.png

第三章:Gradle 打包 javadoc

3.1 概述

  • 一个完整的项目在进行打包的时候一个会有三个 *.jar 文件:主程序(gradle-1.0.jar)、源代码(gradle-1.0-sources.jar)和文档(gradle-1.0-javadoc.jar),如果要生成程序的 javadoc 文档,那么首先一定需要在项目中追加相应的文档说明,同时还需要在 build.gradle 文件中定义有相关的任务处理。

3.2 文档注释

  • 略(一般项目中都需要写文档注释的)。

3.3 Gradle 的任务配置

  • 如果要想生成 javadoc,则需要配置有相关的任务,Gradle 里面已经有了这样的内置任务,我们只需要对 javadoc 任务做一个继承处理即可,修改 build.gradle 文件:
  1. task javaDocTask(type: Javadoc){
  2. source sourceSets.main.allJava // 定义所有的 Java 源代码的路径
  3. }
  4. tasks.withType(Javadoc){ // 文档生成一定要有乱码处理
  5. options.encoding = "UTF-8"
  6. }
  7. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  8. options.encoding = "UTF-8"
  9. }
  • 程序执行命令:
  1. gradle javaDocTask
  • 程序执行结果:

3.png

  • 当命令执行完成之后,会自动在 build/docs/javadoc 目录下生成所有的 JavaDoc 文档。

3.4 打包 JavaDoc

  • 最终在进行项目发布的时候,肯定要生成 javadoc 的 jar 文件,此时就需要定义一个打包任务,修改 build.gradle 文件:
  1. task javaDocJar(type: Jar, dependsOn: javaDocTask) { // 先生成 javadoc,才可以打包
  2. archiveClassifier.set 'javadoc' // 文件的分类
  3. from javaDocTask.destinationDir // 通过 javaDocTask 任务中找到目标路径
  4. }

3.5 命令整合

  • javadoc 的生成也应该在整个压缩结构文件生成的同时进行创建,修改 build.gradle 文件:
  1. task javaDocTask(type: Javadoc) {
  2. source sourceSets.main.allJava // 定义所有的 Java 源代码的路径
  3. }
  4. tasks.withType(Javadoc) { // 文档生成一定要有乱码处理
  5. options.encoding = "UTF-8"
  6. }
  7. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  8. options.encoding = "UTF-8"
  9. }
  10. task javaDocJar(type: Jar, dependsOn: javaDocTask) { // 先生成 javadoc,才可以打包
  11. archiveClassifier.set 'javadoc' // 文件的分类
  12. from javaDocTask.destinationDir // 通过 javaDocTask 任务中找到目标路径
  13. }
  14. artifacts { // 最终的打包操作任务
  15. archives sourceJar
  16. archives javaDocJar
  17. }
  • 完整的 build.gradle 文件:
  1. plugins {
  2. id 'java' // 配置的是一个 Java 插件(Java 项目)
  3. id 'java-library'
  4. }
  5. ext {
  6. jdkVersion = JavaVersion.VERSION_1_8 // 传统的 JDK 版本都是需要自己编写字符串的,而 Gradle 中提供了这样的操作
  7. }
  8. apply from: 'dependencies.gradle' // 引入所有的依赖文件
  9. configurations { // 进行依赖的配置
  10. implementation {
  11. canBeConsumed = true
  12. canBeResolved = true
  13. }
  14. }
  15. group 'com.github.fairy.era' // 组织名称
  16. version '1.0' // 项目版本
  17. // 定义一个公共的变量描述当前使用的 JDK 版本
  18. sourceCompatibility = jdkVersion
  19. targetCompatibility = jdkVersion
  20. repositories { // 仓库配置
  21. mavenCentral()
  22. }
  23. dependencies { // 依赖管理
  24. // compile gradleApi()
  25. /* junit 5 */
  26. testImplementation( // 如果有多个依赖,使用 , 隔开
  27. libraries.'junit-jupiter'
  28. )
  29. /* druid */
  30. implementation( // 如果有多个依赖,使用 , 隔开
  31. libraries.'druid'
  32. )
  33. }
  34. def mainClassName = 'com.github.fairy.era.GradleMain' // 程序的主类名称
  35. jar {
  36. archivesBaseName = 'gradle' // 生成的 jar 文件名称,如果不写此名称则使用项目名称
  37. manifestContentCharset = 'UTF-8' // 设置整个文件的编码
  38. metadataCharset = 'UTF-8' // 元数据设置编码
  39. manifest {
  40. attributes 'Manifest-Version': getArchiveVersion().getOrNull(), // 程序版本号
  41. 'Main-Class': "${mainClassName}",// 程序主类名称
  42. 'Implementation-Title': 'hello-gradle',// 程序主类名称
  43. 'Implementation-Version': archiveVersion // 版本编号
  44. }
  45. into('lib') { // 将程序锁需要的第三方组件包配置到 lib 目录之中
  46. from configurations.compileClasspath
  47. }
  48. }
  49. test { // 进行测试任务的配置
  50. useJUnitPlatform() // 使用 Junit 平台
  51. }
  52. sourceSets { // 建立源代码的目录集合
  53. main {
  54. java {
  55. srcDirs = ['src/main/java']
  56. }
  57. resources {
  58. srcDirs = ['src/main/resources', 'src/main/config']
  59. }
  60. }
  61. }
  62. // 最终生成的 jar 文件名称:baseName-version-classifier.extension
  63. task sourceJar(type: Jar, dependsOn: classes) { // 定义一个源代码的打包任务,并依赖于 classes 这种 Gradle 内置的任务
  64. archiveClassifier.set 'sources' // 文件的分类
  65. from sourceSets.main.allSource // 所有源代码的读取路径
  66. }
  67. task javaDocTask(type: Javadoc) {
  68. source sourceSets.main.allJava // 定义所有的 Java 源代码的路径
  69. }
  70. tasks.withType(Javadoc) { // 文档生成一定要有乱码处理
  71. options.encoding = "UTF-8"
  72. }
  73. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  74. options.encoding = "UTF-8"
  75. }
  76. task javaDocJar(type: Jar, dependsOn: javaDocTask) { // 先生成 javadoc,才可以打包
  77. archiveClassifier.set 'javadoc' // 文件的分类
  78. from javaDocTask.destinationDir // 通过 javaDocTask 任务中找到目标路径
  79. }
  80. artifacts { // 最终的打包操作任务
  81. archives sourceJar
  82. archives javaDocJar
  83. }
  • 程序执行命令:
  1. gradle clean build -x test
  • 程序执行结果:

4.png

第四章:Gradle 程序测试控制

4.1 概述

  • 在 Gradle 项目中所有的代码都要有相应的测试用例存在,但是如果说在一些环境下测试用例可能无法正常执行,那么面对这样的情况,就需要每次在编译打包的时候都使用 -x test 来跳过测试。
  • 在 Maven 里面有一种插件,通过配置可以避免执行测试的代码,但是在 Gradle 中并没有这样的插件,如果要想实现测试代码的跳过,就需要手工编写程序。

4.2 错误测试

  • 为了更好的说明问题,首先编写一个错误的测试代码:
  1. package com.github.era.fairy.service;
  2. import com.github.fairy.era.service.IMessageService;
  3. import com.github.fairy.era.service.impl.MessageServiceImpl;
  4. import org.junit.jupiter.api.Assertions;
  5. import org.junit.jupiter.api.Test;
  6. /**
  7. * @author 许大仙
  8. * @version 1.0
  9. * @since 2021-12-21 08:43
  10. */
  11. public class MessageServiceTest {
  12. @Test
  13. public void test() {
  14. IMessageService messageService = new MessageServiceImpl();
  15. Assertions.assertEquals("你好啊", messageService.echo("Gradle"));
  16. }
  17. }
  • 程序执行结果:
  1. > Task :compileJava UP-TO-DATE
  2. > Task :processResources UP-TO-DATE
  3. > Task :classes UP-TO-DATE
  4. > Task :compileTestJava
  5. > Task :processTestResources NO-SOURCE
  6. > Task :testClasses
  7. > Task :test FAILED
  8. expected: <你好啊> but was: <hello Gradle>
  9. 预期:你好啊
  10. 实际:hello Gradle
  11. <点击以查看差异>
  12. org.opentest4j.AssertionFailedError: expected: <你好啊> but was: <hello Gradle>
  13. at com.github.era.fairy.service.MessageServiceTest.test(MessageServiceTest.java:18)
  14. at java.util.ArrayList.forEach(ArrayList.java:1249)
  15. at java.util.ArrayList.forEach(ArrayList.java:1249)
  16. MessageServiceTest > test() FAILED
  17. org.opentest4j.AssertionFailedError at MessageServiceTest.java:18
  18. 1 test completed, 1 failed
  19. FAILURE: Build failed with an exception.
  20. * What went wrong:
  21. Execution failed for task ':test'.
  22. > There were failing tests. See the report at: file:///D:/project/gradle-01/build/reports/tests/test/index.html
  23. * Try:
  24. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
  25. * Get more help at https://help.gradle.org
  26. BUILD FAILED in 1s
  27. 4 actionable tasks: 2 executed, 2 up-to-date

4.3 代码影响

  • 这样的程序代码在进行编译打包时候,一定会带来无法正常运行的问题。
  • 程序执行命令:
  1. gradle clean build
  • 程序执行结果:
  1. Execution failed for task ':test'.
  2. > There were failing tests. See the report at: file:///D:/project/gradle-01/build/reports/tests/test/index.html
  3. * Try:
  4. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
  • 传统的解决方式就是使用 -x test 命令参数来进行控制,但是太麻烦了。

4.4 测试的控制任务

  • 如果要想解决当前测试代码对整个程序的影响,可以考虑做一个开关,修改 build.gradle 文件:
  1. gradle.taskGraph.whenReady { // 在所有的操作准备好之后触发
  2. tasks.each { task ->
  3. if (task.name.contains('test')) { // 如果发现有 test 任务,就跳过
  4. task.enabled = false // 当前任务不执行
  5. }
  6. }
  7. }
  • 当项目中配置了这样的处理之后,实际上最终所有的程序的测试都会失效,因为只要发现是测试的指令,就会关闭任务处理。

第五章:Gradle 多环境配置管理

5.1 概述

  • 一个项目如果要想正常使用,则一般会经历:开发环境、测试环境和线上环境,不同的环境对于一些程序的配置信息也有所不同,那么这样的操作都可以通过 profile 来进行配置。
  • 按照正常的开发逻辑,应该将所有的网络服务器的信息,保存在不同的 profile 文件里面,例如:现在假设在 src/main 目录下创建一个 profiles 公共目录。
  1. .
  2. |-- LICENSE
  3. |-- build.gradle
  4. |-- gradle
  5. | `-- wrapper
  6. | |-- gradle-wrapper.jar
  7. | `-- gradle-wrapper.properties
  8. |-- gradlew
  9. |-- gradlew.bat
  10. |-- settings.gradle
  11. `-- src
  12. |-- main
  13. | |-- config
  14. | | |-- database.properties
  15. | | |-- dubbo.properties
  16. | | `-- redis.properties
  17. | |-- java
  18. | |-- profiles # 公共目录
  19. | | |-- dev # 开发环境
  20. | | | `-- config
  21. | | | `-- database.properties
  22. | | |-- prod # 生产环境
  23. | | | `-- config
  24. | | | `-- database.properties
  25. | | `-- test # 测试环境
  26. | | `-- config
  27. | | `-- database.properties
  28. | `-- resources
  29. `-- test
  30. |-- java
  31. `-- resources

5.2 定义 profile

  • 以上的三个不同的属性文件在项目中的所有 key 的内容是相同的,不同的仅仅是 key 对应的 value ,在程序执行的时候就可以根据不同的环境实现配置的切换。
  • src/main/profiles/dev/config/database.properties:
  1. druid.database.name=gradle-dev
  2. druid.database.username=gradle-dev
  • src/main/profiles/test/config/database.properties:
  1. druid.database.name=gradle-prod
  2. druid.database.username=gradle-prod
  • src/main/profiles/prod/config/database.properties:
  1. druid.database.name=gradle-test
  2. druid.database.username=gradle-test

5.3 Gradle 配置

  • 如果要想让当前的这个 profile 路径生效,则一定要修改 build.gradle 配置文件,在这个配置文件里面定义源代码的访问路径,但是这个路径需要注意的是,里面的 profile 名称是需要动态变更的。 | 环境 | profile 路径 | | —- | —- | | 开发环境 | src/main/profiles/dev
    /config/database.properties | | 测试环境 | src/main/profiles/test
    /config/database.properties | | 生产环境 | src/main/profiles/prod
    /config/database.properties |
  • 修改 build.gradle 文件,获取 env 环境属性:
  1. def env = System.getProperty("env")?:'dev' // 获取 env 的环境属性
  • 对于当前可以接受的 env 环境属性,实际上就属于最终的 src/main/profiles/xxx 的动态内容,最终所需要的 profile 的具体内容就是由这个变量决定的,那么修改 build.gradle 文件:
  1. sourceSets { // 建立源代码的目录集合
  2. main {
  3. java {
  4. srcDirs = ['src/main/java']
  5. }
  6. resources {
  7. srcDirs = ['src/main/resources', 'src/main/config', "src/main/profiles/${env}"]
  8. }
  9. }
  10. }
  • 完整的 build.gradle 文件:
  1. plugins {
  2. id 'java' // 配置的是一个 Java 插件(Java 项目)
  3. id 'java-library'
  4. }
  5. ext {
  6. jdkVersion = JavaVersion.VERSION_1_8 // 传统的 JDK 版本都是需要自己编写字符串的,而 Gradle 中提供了这样的操作
  7. }
  8. apply from: 'dependencies.gradle' // 引入所有的依赖文件
  9. configurations { // 进行依赖的配置
  10. implementation {
  11. canBeConsumed = true
  12. canBeResolved = true
  13. }
  14. }
  15. group 'com.github.fairy.era' // 组织名称
  16. version '1.0' // 项目版本
  17. // 定义一个公共的变量描述当前使用的 JDK 版本
  18. sourceCompatibility = jdkVersion
  19. targetCompatibility = jdkVersion
  20. def env = System.getProperty("env")?:'dev' // 获取 env 的环境属性
  21. repositories { // 仓库配置
  22. mavenCentral()
  23. }
  24. dependencies { // 依赖管理
  25. // compile gradleApi()
  26. /* junit 5 */
  27. testImplementation( // 如果有多个依赖,使用 , 隔开
  28. libraries.'junit-jupiter'
  29. )
  30. /* druid */
  31. implementation( // 如果有多个依赖,使用 , 隔开
  32. libraries.'druid'
  33. )
  34. }
  35. def mainClassName = 'com.github.fairy.era.GradleMain' // 程序的主类名称
  36. jar {
  37. archivesBaseName = 'gradle' // 生成的 jar 文件名称,如果不写此名称则使用项目名称
  38. manifestContentCharset = 'UTF-8' // 设置整个文件的编码
  39. metadataCharset = 'UTF-8' // 元数据设置编码
  40. manifest {
  41. attributes 'Manifest-Version': getArchiveVersion().getOrNull(), // 程序版本号
  42. 'Main-Class': "${mainClassName}",// 程序主类名称
  43. 'Implementation-Title': 'hello-gradle',// 程序主类名称
  44. 'Implementation-Version': archiveVersion // 版本编号
  45. }
  46. into('lib') { // 将程序锁需要的第三方组件包配置到 lib 目录之中
  47. from configurations.compileClasspath
  48. }
  49. }
  50. test { // 进行测试任务的配置
  51. useJUnitPlatform() // 使用 Junit 平台
  52. }
  53. sourceSets { // 建立源代码的目录集合
  54. main {
  55. java {
  56. srcDirs = ['src/main/java']
  57. }
  58. resources {
  59. srcDirs = ['src/main/resources', 'src/main/config', "src/main/profiles/${env}"]
  60. }
  61. }
  62. }
  63. gradle.taskGraph.whenReady { // 在所有的操作准备好之后触发
  64. tasks.each { task ->
  65. if (task.name.contains('test')) { // 如果发现有 test 任务,就跳过
  66. task.enabled = true // 当前任务不执行
  67. }
  68. }
  69. }
  70. // 最终生成的 jar 文件名称:baseName-version-classifier.extension
  71. task sourceJar(type: Jar, dependsOn: classes) { // 定义一个源代码的打包任务,并依赖于 classes 这种 Gradle 内置的任务
  72. archiveClassifier.set 'sources' // 文件的分类
  73. from sourceSets.main.allSource // 所有源代码的读取路径
  74. }
  75. task javaDocTask(type: Javadoc) {
  76. source sourceSets.main.allJava // 定义所有的 Java 源代码的路径
  77. }
  78. tasks.withType(Javadoc) { // 文档生成一定要有乱码处理
  79. options.encoding = "UTF-8"
  80. }
  81. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  82. options.encoding = "UTF-8"
  83. }
  84. task javaDocJar(type: Jar, dependsOn: javaDocTask) { // 先生成 javadoc,才可以打包
  85. archiveClassifier.set 'javadoc' // 文件的分类
  86. from javaDocTask.destinationDir // 通过 javaDocTask 任务中找到目标路径
  87. }
  88. artifacts { // 最终的打包操作任务
  89. archives sourceJar
  90. archives javaDocJar
  91. }

5.4 打包处理

  • 此时给出的是一个 Java 环境属性,所以环境属性可以采用 -D属性名称 = 内容 的形式来进行处理,而后要进行程序的打包配置。
  • 开发环境打包命令(任选其一即可):
  1. gradle clean build
  1. gradle clean build -Denv=dev
  • 测试环境打包命令:
  1. gradle clean build -Denv=test
  • 生产环境打包命令:
  1. gradle clean build -Denv=prod

5.5 依赖配置

  • 长期以来如果使用 Maven 都会发现有一个核心问题:依赖库的版本永远都是需要固定配置,即使有不同的 profile,依赖库也是无法变更的;但是在 Gradle 里面,将这个问题解决了,在之前为了进行依赖的统一管理,提供有一个 dependencies.gradle 的配置文件,那么如果要想实现不同版本的切换,就可以通过这样的文件形式来进行控制。
  • 下面建立 dependencies-xxx.gradle 的配置文件,其中 xxx 代表 dev、test 和 prod。
  • dependencies-dev.gradle 的内容如下:
  1. // 定义所有要使用的版本号
  2. ext.versions = [
  3. junitJupiterVersion: '5.8.0',
  4. druidVersion : '1.2.6'
  5. ]
  6. // 定义所有的依赖库
  7. ext.libraries = [
  8. /* junit 5 */
  9. 'junit-jupiter': "org.junit.jupiter:junit-jupiter:${versions.junitJupiterVersion}",
  10. /* druid */
  11. druid : "com.alibaba:druid:${versions.druidVersion}"
  12. ]
  • dependencies-test .gradle 的内容如下:
  1. // 定义所有要使用的版本号
  2. ext.versions = [
  3. junitJupiterVersion: '5.8.1',
  4. druidVersion : '1.2.7'
  5. ]
  6. // 定义所有的依赖库
  7. ext.libraries = [
  8. /* junit 5 */
  9. 'junit-jupiter': "org.junit.jupiter:junit-jupiter:${versions.junitJupiterVersion}",
  10. /* druid */
  11. druid : "com.alibaba:druid:${versions.druidVersion}"
  12. ]
  • dependencies-prod.gradle 的内容如下:
  1. // 定义所有要使用的版本号
  2. ext.versions = [
  3. junitJupiterVersion: '5.8.2',
  4. druidVersion : '1.2.8'
  5. ]
  6. // 定义所有的依赖库
  7. ext.libraries = [
  8. /* junit 5 */
  9. 'junit-jupiter': "org.junit.jupiter:junit-jupiter:${versions.junitJupiterVersion}",
  10. /* druid */
  11. druid : "com.alibaba:druid:${versions.druidVersion}"
  12. ]

5.png

5.6 动态导入

  • 修改 build.gradle 文件,针对于依赖配置库进行动态配置:
  1. def env = System.getProperty("env")?:'dev' // 获取 env 的环境属性
  2. apply from: "dependencies-${env}.gradle" // 引入所有的依赖文件
  • 开发环境打包命令:
  1. gradle clean build
  1. gradle clean build -Denv=dev
  • 测试环境打包命令:
  1. gradle clean build -Denv=test
  • 生产环境打包命令:
  1. gradle clean build -Denv=prod
  • 完成的 build.gradle 文件:
  1. plugins {
  2. id 'java' // 配置的是一个 Java 插件(Java 项目)
  3. id 'java-library'
  4. }
  5. ext {
  6. jdkVersion = JavaVersion.VERSION_1_8 // 传统的 JDK 版本都是需要自己编写字符串的,而 Gradle 中提供了这样的操作
  7. }
  8. def env = System.getProperty("env")?:'dev' // 获取 env 的环境属性
  9. apply from: "dependencies-${env}.gradle" // 引入所有的依赖文件
  10. configurations { // 进行依赖的配置
  11. implementation {
  12. canBeConsumed = true
  13. canBeResolved = true
  14. }
  15. }
  16. group 'com.github.fairy.era' // 组织名称
  17. version '1.0' // 项目版本
  18. // 定义一个公共的变量描述当前使用的 JDK 版本
  19. sourceCompatibility = jdkVersion
  20. targetCompatibility = jdkVersion
  21. repositories { // 仓库配置
  22. mavenCentral()
  23. }
  24. dependencies { // 依赖管理
  25. // compile gradleApi()
  26. /* junit 5 */
  27. testImplementation( // 如果有多个依赖,使用 , 隔开
  28. libraries.'junit-jupiter'
  29. )
  30. /* druid */
  31. implementation( // 如果有多个依赖,使用 , 隔开
  32. libraries.'druid'
  33. )
  34. }
  35. def mainClassName = 'com.github.fairy.era.GradleMain' // 程序的主类名称
  36. jar {
  37. archivesBaseName = 'gradle' // 生成的 jar 文件名称,如果不写此名称则使用项目名称
  38. manifestContentCharset = 'UTF-8' // 设置整个文件的编码
  39. metadataCharset = 'UTF-8' // 元数据设置编码
  40. manifest {
  41. attributes 'Manifest-Version': getArchiveVersion().getOrNull(), // 程序版本号
  42. 'Main-Class': "${mainClassName}",// 程序主类名称
  43. 'Implementation-Title': 'hello-gradle',// 程序主类名称
  44. 'Implementation-Version': archiveVersion // 版本编号
  45. }
  46. into('lib') { // 将程序锁需要的第三方组件包配置到 lib 目录之中
  47. from configurations.compileClasspath
  48. }
  49. }
  50. test { // 进行测试任务的配置
  51. useJUnitPlatform() // 使用 Junit 平台
  52. }
  53. sourceSets { // 建立源代码的目录集合
  54. main {
  55. java {
  56. srcDirs = ['src/main/java']
  57. }
  58. resources {
  59. srcDirs = ['src/main/resources', 'src/main/config', "src/main/profiles/${env}"]
  60. }
  61. }
  62. }
  63. gradle.taskGraph.whenReady { // 在所有的操作准备好之后触发
  64. tasks.each { task ->
  65. if (task.name.contains('test')) { // 如果发现有 test 任务,就跳过
  66. task.enabled = true // 当前任务不执行
  67. }
  68. }
  69. }
  70. // 最终生成的 jar 文件名称:baseName-version-classifier.extension
  71. task sourceJar(type: Jar, dependsOn: classes) { // 定义一个源代码的打包任务,并依赖于 classes 这种 Gradle 内置的任务
  72. archiveClassifier.set 'sources' // 文件的分类
  73. from sourceSets.main.allSource // 所有源代码的读取路径
  74. }
  75. task javaDocTask(type: Javadoc) {
  76. source sourceSets.main.allJava // 定义所有的 Java 源代码的路径
  77. }
  78. tasks.withType(Javadoc) { // 文档生成一定要有乱码处理
  79. options.encoding = "UTF-8"
  80. }
  81. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  82. options.encoding = "UTF-8"
  83. }
  84. task javaDocJar(type: Jar, dependsOn: javaDocTask) { // 先生成 javadoc,才可以打包
  85. archiveClassifier.set 'javadoc' // 文件的分类
  86. from javaDocTask.destinationDir // 通过 javaDocTask 任务中找到目标路径
  87. }
  88. artifacts { // 最终的打包操作任务
  89. archives sourceJar
  90. archives javaDocJar
  91. }