第一章:Gradle 创建可执行 jar 文件

1.1 概述

  • 如果要想创建可执行的 jar 文件,一般需要考虑将第三方的组件保存在 jar 文件之中,所以除了基本的程序打包之外,还需要考虑到将第三方的 jar 文件一起打包的操作。

1.2 依赖的配置

  • 在项目中引入 druid 的组件,修改 build.gradle 文件:
  1. plugins {
  2. id 'java' // 配置的是一个 Java 插件(Java 项目)
  3. }
  4. group 'com.github.fairy.era' // 组织名称
  5. version '1.0' // 项目版本
  6. sourceCompatibility = 1.8 // 源代码版本
  7. repositories { // 仓库配置
  8. mavenCentral()
  9. }
  10. dependencies { // 依赖管理
  11. /* junit 5 */
  12. testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.8.2'
  13. /* druid */
  14. implementation group: 'com.alibaba', name: 'druid', version: '1.2.8'
  15. }
  16. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  17. options.encoding = "UTF-8"
  18. }
  19. test { // 进行测试任务的配置
  20. useJUnitPlatform() // 使用 Junit 平台
  21. }
  22. sourceSets { // 建立源代码的目录集合
  23. main {
  24. java {
  25. srcDirs = ['src/main/java']
  26. }
  27. resources {
  28. srcDirs = ['src/main/resources', 'src/main/config']
  29. }
  30. }
  31. }

1.3 启动类

  • 为了方便 jar 文件的执行,一般都会定义有一个程序启动类:
  1. package com.github.fairy.era;
  2. /**
  3. * @author 许大仙
  4. * @version 1.0
  5. * @since 2021-12-24 15:36
  6. */
  7. public class GradleMain {
  8. public static void main(String[] args) {
  9. System.out.println("你好啊,Gradle");
  10. }
  11. }

1.3 Gradle 配置

  • 如果现在要想项目打包成一个可执行的 jar 文件,就需要修改 build.gradle 文件,加入各种配置项:
  1. // 定义一个公共的变量描述当前使用的 JDK 版本
  2. def jdkVersion = 1.8
  3. sourceCompatibility = jdkVersion // 源代码版本
  4. targetCompatibility = jdkVersion // 目标版本
  1. def mainClassName = 'com.github.fairy.era.GradleMain' // 程序的主类名称
  2. jar {
  3. archivesBaseName = 'gradle' // 生成的 jar 文件名称,如果不写此名称则使用项目名称
  4. manifestContentCharset = 'UTF-8' // 设置整个文件的编码
  5. metadataCharset = 'UTF-8' // 元数据设置编码
  6. manifest {
  7. attributes(['Manifest-Version' : getArchiveVersion().getOrNull(), // 程序版本号
  8. 'Main-Class' : "$mainClassName", // 程序主类名称
  9. 'Implementation-Title' : 'hello-gradle', // 实现标题
  10. 'Implementation-Version': archiveVersion // 实现的内部版本号
  11. ])
  12. }
  13. into('lib') { // 将程序锁需要的第三方组件包配置到 lib 目录之中
  14. from configurations.compileClasspath
  15. }
  16. }

1.4 打包

  • 通过 Gradle 对当前的项目进行打包处理。
  • 程序执行命令:
  1. gradle clean build
  • 程序执行结果:

1.png

  • 在使用 build 进行项目构建的时候会自动找到里面的 jar 任务进行项目的构建处理,当构建成功后会得到一个 gradle-1.0.jar 文件,这是一个可执行的 jar 文件。

1.5 执行 jar

  • 既然生成的是一个可执行的 jar 文件,那么直接通过本地的 JDK 提供的命令执行当前的程序:
  1. java -jar gradle-1.0.jar

2.gif

第二章:Gradle 依赖库打包范围

2.1 概述

  • 在 Maven 中所有的依赖库并不是最终都会直接进行打包,会根据不同的范围有着不同的作用,同理对于 Gradle 来说,也是一样。
  • 对于当前使用的 build.gradle 配置文件来说,引入了如下的几个依赖:
  1. dependencies { // 依赖管理
  2. /* junit 5 */
  3. testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.8.2'
  4. /* druid */
  5. implementation group: 'com.alibaba', name: 'druid', version: '1.2.8'
  6. }
  • 此时的程序一共提供了 2 个依赖库,但是最终在打包生成 jar 包的时候里面只有一个 druid.jar 文件,那么主要的原因在于 druid 使用了 implementation 打包范围,而对于 testImplementation 由于只是工作在测试环境,所以没有必要将其打包在最终的程序文件中。

2.2 Gradle 支持的打包范围

打包范围(老版本) 描述 打包范围(新版本 描述
compile 依赖的库文件在编译及运行时都需要,前提:apply plugin: ‘war’ 或 apply plugin: ‘java’ implementation A 依赖 B ,B 依赖 C ,如果 B 依赖 C 使用的是 implementation ,那么在 A 中是访问不到 C 中的方法的,如果需要访问,请使用 api 依赖。
compile 依赖的库文件在编译时需要,但是在运行时不需要,前提:apply plugin: ‘war’ api 此配置的行为类似于 compile
(现已弃用)
provided 依赖的库文件在编译时需要,但是在运行时不需要,前提:apply plugin: ‘war’ compileOnly 此配置的行为类似于 provided
(现已弃用)
runtime 依赖的库文件在编译时需要,但是在编译时不需要,前提:apply plugin: ‘java’ runtimeOnly 此配置的行为类似于 runtime
(现已弃用)
testCompile 依赖库在测试的时候需要 testImplementation 此配置的行为类似于 testCompile
(现已弃用)
debugCompile 依赖文件在 debug 模式下生效 debugImplementation 此配置的行为类似于 debugCompile
(现已弃用)
releaseCompile 赖文件在最终 Release 模式下生效 releaseImplementation 此配置的行为类似于 releaseCompile
(现已弃用)

2.3 本地 jar

  • 默认情况下所有项目中需要使用到的 Gradle 依赖全部都是通过网络下载的,但是如果说现在某些依赖已经在本地了,不希望再去网络进行引用,Gradle 也是支持这一功能的。
  • ① 在项目中添加一个新的目录 libs 。

3.png

  • ② 将本地需要导入的 jar 文件保存在此目录之中。

4.png

  • ③ 修改 build.gradle 配置文件,在依赖配置上进行本地的引用:
  1. dependencies { // 依赖管理
  2. /* junit 5 */
  3. testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.8.2'
  4. /* druid */
  5. implementation group: 'com.alibaba', name: 'druid', version: '1.2.8'
  6. /* 进行本地的引用 */
  7. implementation fileTree(dir: 'libs', includes: ['*.jar'])
  8. }
  • 程序执行命令:
  1. gradle clean build
  • 程序执行结果:

5.png

  • 完整的 build.gradle 文件:
  1. plugins {
  2. id 'java' // 配置的是一个 Java 插件(Java 项目)
  3. }
  4. group 'com.github.fairy.era' // 组织名称
  5. version '1.0' // 项目版本
  6. // 定义一个公共的变量描述当前使用的 JDK 版本
  7. def jdkVersion = 1.8
  8. sourceCompatibility = jdkVersion // 源代码版本
  9. targetCompatibility = jdkVersion // 目标版本
  10. repositories { // 仓库配置
  11. mavenCentral()
  12. }
  13. dependencies { // 依赖管理
  14. /* junit 5 */
  15. testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.8.2'
  16. /* druid */
  17. implementation group: 'com.alibaba', name: 'druid', version: '1.2.8'
  18. implementation fileTree(dir: 'libs', includes: ['*.jar'])
  19. }
  20. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  21. options.encoding = "UTF-8"
  22. }
  23. def mainClassName = 'com.github.fairy.era.GradleMain' // 程序的主类名称
  24. jar {
  25. archivesBaseName = 'gradle' // 生成的 jar 文件名称,如果不写此名称则使用项目名称
  26. manifestContentCharset = 'UTF-8' // 设置整个文件的编码
  27. metadataCharset = 'UTF-8' // 元数据设置编码
  28. manifest {
  29. attributes(['Manifest-Version' : getArchiveVersion().getOrNull(), // 程序版本号
  30. 'Main-Class' : "$mainClassName", // 程序主类名称
  31. 'Implementation-Title' : 'hello-gradle', // 实现标题
  32. 'Implementation-Version': archiveVersion // 实现的内部版本号
  33. ])
  34. }
  35. into('lib') { // 将程序锁需要的第三方组件包配置到 lib 目录之中
  36. from configurations.compileClasspath
  37. }
  38. }
  39. test { // 进行测试任务的配置
  40. useJUnitPlatform() // 使用 Junit 平台
  41. }
  42. sourceSets { // 建立源代码的目录集合
  43. main {
  44. java {
  45. srcDirs = ['src/main/java']
  46. }
  47. resources {
  48. srcDirs = ['src/main/resources', 'src/main/config']
  49. }
  50. }
  51. }

2.4 api

  • 在早期的 Gradle 版本中推荐使用的是 compile ,但是时过境迁,目前的 Gradle 推荐使用的是 implementation,然而 implementation 不会将依赖进行传递,可是我们又需要将依赖进行传递,那么就需要使用 api 了(需要在项目中引入新的插件)。
  • 引入新的插件,修改 build.gradle 文件:
  1. plugins {
  2. id 'java' // 配置的是一个 Java 插件(Java 项目)
  3. id 'java-library' // 引入一个新的插件
  4. }
  • 修改引入,修改 build.gradle 文件:
  1. dependencies { // 依赖管理
  2. /* junit 5 */
  3. testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.8.2'
  4. /* druid */
  5. api group: 'com.alibaba', name: 'druid', version: '1.2.8'
  6. implementation fileTree(dir: 'libs', includes: ['*.jar'])
  7. }
  • 程序执行命令:
  1. gradle clean build
  • 程序执行结果:

6.png

2.5 依赖信息

  • 在一个项目中肯定会引入大量的第三方的依赖,对于这些依赖信息可以直接通过 gradle 命令查看。
  • 程序执行命令:
  1. gradle -q dependencies
  • 程序执行结果:
  1. 10:52:49: 正在执行 'dependencies -q'
  2. ------------------------------------------------------------
  3. Root project
  4. ------------------------------------------------------------
  5. annotationProcessor - Annotation processors and their dependencies for source set 'main'.
  6. No dependencies
  7. api - API dependencies for source set 'main'. (n)
  8. \--- com.alibaba:druid:1.2.8 (n)
  9. apiElements - API elements for main. (n)
  10. No dependencies
  11. archives - Configuration for archive artifacts. (n)
  12. No dependencies
  13. compileClasspath - Compile classpath for source set 'main'.
  14. \--- com.alibaba:druid:1.2.8
  15. compileOnly - Compile only dependencies for source set 'main'. (n)
  16. No dependencies
  17. default - Configuration for default artifacts. (n)
  18. No dependencies
  19. implementation - Implementation only dependencies for source set 'main'. (n)
  20. \--- unspecified (n)
  21. runtimeClasspath - Runtime classpath of source set 'main'.
  22. \--- com.alibaba:druid:1.2.8
  23. runtimeElements - Elements of runtime for main. (n)
  24. No dependencies
  25. runtimeOnly - Runtime only dependencies for source set 'main'. (n)
  26. No dependencies
  27. testAnnotationProcessor - Annotation processors and their dependencies for source set 'test'.
  28. No dependencies
  29. testCompileClasspath - Compile classpath for source set 'test'.
  30. +--- com.alibaba:druid:1.2.8
  31. \--- org.junit.jupiter:junit-jupiter:5.8.2
  32. +--- org.junit:junit-bom:5.8.2
  33. | +--- org.junit.jupiter:junit-jupiter:5.8.2 (c)
  34. | +--- org.junit.jupiter:junit-jupiter-api:5.8.2 (c)
  35. | +--- org.junit.jupiter:junit-jupiter-params:5.8.2 (c)
  36. | \--- org.junit.platform:junit-platform-commons:1.8.2 (c)
  37. +--- org.junit.jupiter:junit-jupiter-api:5.8.2
  38. | +--- org.junit:junit-bom:5.8.2 (*)
  39. | +--- org.opentest4j:opentest4j:1.2.0
  40. | +--- org.junit.platform:junit-platform-commons:1.8.2
  41. | | +--- org.junit:junit-bom:5.8.2 (*)
  42. | | \--- org.apiguardian:apiguardian-api:1.1.2
  43. | \--- org.apiguardian:apiguardian-api:1.1.2
  44. \--- org.junit.jupiter:junit-jupiter-params:5.8.2
  45. +--- org.junit:junit-bom:5.8.2 (*)
  46. +--- org.junit.jupiter:junit-jupiter-api:5.8.2 (*)
  47. \--- org.apiguardian:apiguardian-api:1.1.2
  48. testCompileOnly - Compile only dependencies for source set 'test'. (n)
  49. No dependencies
  50. testImplementation - Implementation only dependencies for source set 'test'. (n)
  51. \--- org.junit.jupiter:junit-jupiter:5.8.2 (n)
  52. testRuntimeClasspath - Runtime classpath of source set 'test'.
  53. +--- com.alibaba:druid:1.2.8
  54. \--- org.junit.jupiter:junit-jupiter:5.8.2
  55. +--- org.junit:junit-bom:5.8.2
  56. | +--- org.junit.jupiter:junit-jupiter:5.8.2 (c)
  57. | +--- org.junit.jupiter:junit-jupiter-api:5.8.2 (c)
  58. | +--- org.junit.jupiter:junit-jupiter-engine:5.8.2 (c)
  59. | +--- org.junit.jupiter:junit-jupiter-params:5.8.2 (c)
  60. | +--- org.junit.platform:junit-platform-commons:1.8.2 (c)
  61. | \--- org.junit.platform:junit-platform-engine:1.8.2 (c)
  62. +--- org.junit.jupiter:junit-jupiter-api:5.8.2
  63. | +--- org.junit:junit-bom:5.8.2 (*)
  64. | +--- org.opentest4j:opentest4j:1.2.0
  65. | \--- org.junit.platform:junit-platform-commons:1.8.2
  66. | \--- org.junit:junit-bom:5.8.2 (*)
  67. +--- org.junit.jupiter:junit-jupiter-params:5.8.2
  68. | +--- org.junit:junit-bom:5.8.2 (*)
  69. | \--- org.junit.jupiter:junit-jupiter-api:5.8.2 (*)
  70. \--- org.junit.jupiter:junit-jupiter-engine:5.8.2
  71. +--- org.junit:junit-bom:5.8.2 (*)
  72. +--- org.junit.platform:junit-platform-engine:1.8.2
  73. | +--- org.junit:junit-bom:5.8.2 (*)
  74. | +--- org.opentest4j:opentest4j:1.2.0
  75. | \--- org.junit.platform:junit-platform-commons:1.8.2 (*)
  76. \--- org.junit.jupiter:junit-jupiter-api:5.8.2 (*)
  77. testRuntimeOnly - Runtime only dependencies for source set 'test'. (n)
  78. No dependencies
  79. (c) - dependency constraint
  80. (*) - dependencies omitted (listed previously)
  81. (n) - Not resolved (configuration is not meant to be resolved)
  82. A web-based, searchable dependency report is available by adding the --scan option.
  83. 10:52:49: 执行完成 'dependencies -q'

2.6 依赖过滤

  • 有些时候可能并不需要将所有范围的依赖全部进行列出,只希望列出 implementation 的依赖范围,那么可以在依赖列表的时候进行一些参数的配置。
  • 程序执行命令:
  1. gradle -q dependencies --configuration implementation
  • 程序执行结果:
  1. 8:50:36: 正在执行 'dependencies --configuration implementation -q'
  2. ------------------------------------------------------------
  3. Root project
  4. ------------------------------------------------------------
  5. implementation - Implementation only dependencies for source set 'main'. (n)
  6. +--- com.alibaba:druid:1.2.8 (n)
  7. \--- unspecified (n)
  8. (n) - Not resolved (configuration is not meant to be resolved)
  9. A web-based, searchable dependency report is available by adding the --scan option.
  10. 8:50:37: 执行完成 'dependencies --configuration implementation -q'

2.7 依赖查找

  • 一个项目中有可能存在有大量的依赖,那么也可以直接利用 gradle 项目进行指定依赖名称的查找。
  • 程序执行命令:查找项目中是否存在 druid 的依赖
  1. gradle -q dependencyInsight --dependency druid --configuration implementation
  • 程序执行结果:
  1. Execution failed for task ':dependencyInsight'.
  2. > Resolving dependency configuration 'implementation' is not allowed as it is defined as 'canBeResolved=false'.
  3. Instead, a resolvable ('canBeResolved=true') dependency configuration that extends 'implementation' should be resolved.
  4. * Try:
  5. 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.
  • 此时程序会报错,根据提示信息在 build.gradle 中增加如下的配置信息:
  1. configurations {
  2. implementation {
  3. canBeConsumed = true
  4. canBeResolved = true
  5. }
  6. }
  • 再次执行程序命令,程序执行结果:
  1. 9:11:31: 正在执行 'dependencyInsight --dependency druid --configuration implementation -q'
  2. com.alibaba:druid:1.2.8
  3. variant "runtime" [
  4. org.gradle.status = release (not requested)
  5. org.gradle.usage = java-runtime (not requested)
  6. org.gradle.libraryelements = jar (not requested)
  7. org.gradle.category = library (not requested)
  8. ]
  9. com.alibaba:druid:1.2.8
  10. \--- implementation
  11. A web-based, searchable dependency report is available by adding the --scan option.
  12. 9:11:31: 执行完成 'dependencyInsight --dependency druid --configuration implementation -q'
  • 所有的依赖的配置在 Gradle 里面都有其自己的范围,同时也可以通过 Gradle 提供的各种命令进行依赖的查找。

第三章:Gradle 依赖库排除

3.1 概述

  • 在进行依赖库引入的时候,由于各个不同的依赖库有可能去引用同一个依赖文件(最为常见的就是日志组件了),这样就会造成各种的包引入不明确的问题,所有就需要进行一些依赖的排除操作。

3.2 日志依赖

  • 修改 build.gradle 文件,进行一些日志依赖文件的定义:
  1. dependencies { // 依赖管理
  2. testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.8.2'
  3. /* druid */
  4. implementation group: 'com.alibaba', name: 'druid', version: '1.2.8'
  5. /* 日志依赖 */
  6. implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.30'
  7. implementation group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.30'
  8. implementation group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1.7.30'
  9. implementation group: 'org.slf4j', name: 'slf4j-nop', version: '1.7.30'
  10. implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.2'
  11. implementation group: 'org.apache.logging.log4j', name: 'log4j-to-slf4j', version: '2.13.2'
  12. }

3.3 日志文件

  • 如果要想进行日志的显示,还需要配置有一个日志文件:logback.xml ,内容如下:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration debug="false">
  3. <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
  4. <property name="LOG_HOME" value="d://home" />
  5. <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- 控制台输出 -->
  6. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  7. <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
  8. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  9. </encoder>
  10. </appender>
  11. <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 按照每天生成日志文件 -->
  12. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  13. <!--日志文件输出的文件名-->
  14. <FileNamePattern>${LOG_HOME}/Yootk.log.%d{yyyy-MM-dd}.log</FileNamePattern>
  15. <!--日志文件保留天数-->
  16. <MaxHistory>30</MaxHistory>
  17. </rollingPolicy>
  18. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  19. <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
  20. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  21. </encoder>
  22. <!--日志文件最大的大小-->
  23. <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
  24. <MaxFileSize>10MB</MaxFileSize>
  25. </triggeringPolicy>
  26. </appender>
  27. <root level="INFO"> <!-- 日志输出级别 -->
  28. <appender-ref ref="STDOUT,FILE" />
  29. </root>
  30. <root level="ERROR"> <!-- 日志输出级别 -->
  31. <appender-ref ref="FILE" />
  32. </root>
  33. <root level="DEBUG"> <!-- 日志输出级别 -->
  34. <appender-ref ref="FILE" />
  35. </root>
  36. </configuration>

7.png

3.4 编写程序

  • 既然已经配置好了日志相关的依赖以及日志的配置文件,那么就可以直接进行日志的操作了。
  1. package com.github.fairy.era;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. /**
  5. * @author 许大仙
  6. * @version 1.0
  7. * @since 2021-12-24 15:36
  8. */
  9. public class GradleMain {
  10. private static Logger logger = LoggerFactory.getLogger(GradleMain.class);
  11. public static void main(String[] args) {
  12. logger.info("你好啊,Gradle");
  13. }
  14. }
  • 程序执行结果:
  1. Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError. See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.
  • 此时的程序执行会出现依赖库重复的问题,因为发现了两个同样的依赖库:log4j-over-slf4j.jar 和 slf4j-log4j12.jar 。

3.5 依赖排除

  • 如果要想解决上面的问题,那么就需要进行依赖的排除操作,修改 build.gradle 文件(以下方式任选一种即可,因为两种都是 Groovy 语法):
  1. configurations { // 进行依赖的配置
  2. all*.exclude group: 'org.slf4j', module: 'slf4j-log4j12' // 全局的排除设置
  3. implementation {
  4. canBeConsumed = true
  5. canBeResolved = true
  6. }
  7. }
  1. configurations { // 进行依赖的配置
  2. all.collect {configuration -> // 全局的排除设置
  3. configuration.exclude group: 'org.slf4j', module: 'slf4j-log4j12'
  4. }
  5. implementation {
  6. canBeConsumed = true
  7. canBeResolved = true
  8. }
  9. }
  • 此时,引入了一个全局的排除设置,这样就表示在进行依赖引入的时候不在项目中去使用 slf4j-log4j12 的组件包。

3.6 模块排除

  • 以上的操作是针对于一个组织中对应的模块编写的排除操作,那么如果有需求也可以针对于一个模块进行排除,修改 build.gradle 文件:
  1. configurations { // 进行依赖的配置
  2. // 模块排除
  3. implementation.exclude module: 'slf4j-log4j12'
  4. implementation {
  5. canBeConsumed = true
  6. canBeResolved = true
  7. }
  8. }

3.7 依赖排除

  • 可以直接在进行某个依赖配置的时候进行排除,修改 build.gradle 文件:
  1. dependencies { // 依赖管理
  2. testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.8.2'
  3. /* druid */
  4. implementation group: 'com.alibaba', name: 'druid', version: '1.2.8'
  5. implementation fileTree(dir: 'libs', includes: ['*.jar'])
  6. implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.30'
  7. // 类似于 Maven 的 exclusion 标签
  8. implementation(group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.30') {
  9. exclude module: 'log4j-api'
  10. }
  11. implementation group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1.7.30'
  12. implementation group: 'org.slf4j', name: 'slf4j-nop', version: '1.7.30'
  13. implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.2'
  14. implementation group: 'org.apache.logging.log4j', name: 'log4j-to-slf4j', version: '2.13.2'
  15. }

注意:实际开发中一般还是会使用依赖排除。

第四章:Gradle 依赖库版本号统一管理

4.1 概述

  • 在任何的构建工具中,由于版本编号经常性的需要进行更新,所以就需要对版本号进行统一的管理操作,在 Gradle 里面为了实现这样的版本号的统一管理,可以专门定义一个配置文件,这个配置文件在需要的地方进行进入即可。

4.2 配置文件

  • 在项目中编写一个 config.gradle 的配置文件,内容如下:
  1. ext { // 编写所有的相关扩展操作
  2. jdkVersion = JavaVersion.VERSION_1_8 // 传统的 JDK 版本都是需要自己编写字符串的,而 Gradle 中提供了这样的操作
  3. druidVersion = '1.2.8'
  4. junitJupiterVersion = '5.8.2'
  5. }

8.png

4.3 引入配置

  • 如果想让配置文件中的配置生效,则必须在 build.gradle 配置文件中进入 config.gradle 的引入,在 plugins 下编写,修改 build.gradle 文件:
  1. plugins {
  2. id 'java' // 配置的是一个 Java 插件(Java 项目)
  3. id 'java-library'
  4. }
  5. apply from: 'config.gradle' // 引入一个配置文件
  • 引入此配置文件就相当于将所有的变量全部引入项目之中,那么后面的项目直接使用变量填充即可。

4.4 Gradle 配置

  • 将 config.gradle 中引入的变量直接在 build.gradle 中进行填充处理,修改 build.gradle 文件:
  1. // 定义一个公共的变量描述当前使用的 JDK 版本
  2. sourceCompatibility = jdkVersion
  3. targetCompatibility = jdkVersion
  1. dependencies { // 依赖管理
  2. /* junit 5 */
  3. testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: junitJupiterVersion
  4. /* druid */
  5. implementation group: 'com.alibaba', name: 'druid', version: druidVersion
  6. }

4.5 程序编译

  • 为了检查当前的配置是否生效,可以考虑将代码进行编译操作。
  • 程序执行命令:
  1. gradle clean build
  • 程序执行结果:

9.png

4.6 版本确定

  • 现在已经成功的实现了版本号的统一配置,但是如果要想确定当前的配置是否成功,那么就可以查看类的版本信息的方式来完成,而这种方式就需要进入到类所在的目录中进行控制。
  • 程序执行命令:
  1. javap -verbose GradleMain.class
  • 程序执行结果:
  1. D:\project\gradle-01\build\classes\java\main\com\github\fairy\era>javap -verbose GradleMain.class
  2. Classfile /D:/project/gradle-01/build/classes/java/main/com/github/fairy/era/GradleMain.class
  3. Last modified 2021-12-27; size 582 bytes
  4. MD5 checksum e61e67b8cc83ecad8ccb76f0733acb21
  5. Compiled from "GradleMain.java"
  6. public class com.github.fairy.era.GradleMain
  7. minor version: 0
  8. major version: 52
  9. flags: ACC_PUBLIC, ACC_SUPER
  10. Constant pool:
  11. #1 = Methodref #6.#20 // java/lang/Object."<init>":()V
  12. #2 = Fieldref #21.#22 // java/lang/System.out:Ljava/io/PrintStream;
  13. #3 = String #23 // 你好啊,Gradle
  14. #4 = Methodref #24.#25 // java/io/PrintStream.println:(Ljava/lang/String;)V
  15. #5 = Class #26 // com/github/fairy/era/GradleMain
  16. #6 = Class #27 // java/lang/Object
  17. #7 = Utf8 <init>
  18. #8 = Utf8 ()V
  19. #9 = Utf8 Code
  20. #10 = Utf8 LineNumberTable
  21. #11 = Utf8 LocalVariableTable
  22. #12 = Utf8 this
  23. #13 = Utf8 Lcom/github/fairy/era/GradleMain;
  24. #14 = Utf8 main
  25. #15 = Utf8 ([Ljava/lang/String;)V
  26. #16 = Utf8 args
  27. #17 = Utf8 [Ljava/lang/String;
  28. #18 = Utf8 SourceFile
  29. #19 = Utf8 GradleMain.java
  30. #20 = NameAndType #7:#8 // "<init>":()V
  31. #21 = Class #28 // java/lang/System
  32. #22 = NameAndType #29:#30 // out:Ljava/io/PrintStream;
  33. #23 = Utf8 你好啊,Gradle
  34. #24 = Class #31 // java/io/PrintStream
  35. #25 = NameAndType #32:#33 // println:(Ljava/lang/String;)V
  36. #26 = Utf8 com/github/fairy/era/GradleMain
  37. #27 = Utf8 java/lang/Object
  38. #28 = Utf8 java/lang/System
  39. #29 = Utf8 out
  40. #30 = Utf8 Ljava/io/PrintStream;
  41. #31 = Utf8 java/io/PrintStream
  42. #32 = Utf8 println
  43. #33 = Utf8 (Ljava/lang/String;)V
  44. {
  45. public com.github.fairy.era.GradleMain();
  46. descriptor: ()V
  47. flags: ACC_PUBLIC
  48. Code:
  49. stack=1, locals=1, args_size=1
  50. 0: aload_0
  51. 1: invokespecial #1 // Method java/lang/Object."<init>":()V
  52. 4: return
  53. LineNumberTable:
  54. line 9: 0
  55. LocalVariableTable:
  56. Start Length Slot Name Signature
  57. 0 5 0 this Lcom/github/fairy/era/GradleMain;
  58. public static void main(java.lang.String[]);
  59. descriptor: ([Ljava/lang/String;)V
  60. flags: ACC_PUBLIC, ACC_STATIC
  61. Code:
  62. stack=2, locals=1, args_size=1
  63. 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
  64. 3: ldc #3 // String 你好啊,Gradle
  65. 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  66. 8: return
  67. LineNumberTable:
  68. line 11: 0
  69. line 12: 8
  70. LocalVariableTable:
  71. Start Length Slot Name Signature
  72. 0 9 0 args [Ljava/lang/String;
  73. }
  74. SourceFile: "GradleMain.java"
  • JDK 版本和 major.minor 版本: | JDK 版本 | major.minor version | | —- | —- | | 1.1 | 45 | | 1.2 | 46 | | 1.3 | 47 | | 1.4 | 48 | | 1.5 | 49 | | 1.6 | 50 | | 1.7 | 51 | | 1.8 | 52 |

第五章:Gradle 依赖库集中管理

5.1 概述

  • 虽然可以通过单独的配置文件模式,将所有需要的版本号进行统一的配置,但是从某些严格意义上来讲,如果将所有的依赖都配置在 build.gradle 文件里面,那么随着时间的推移,build.gradle 文件将会变得又臭又长(可以和传统 Maven 项目中的 pom.xml 对比)!!!
  • 在 Gradle 中考虑到了传统的 Maven 所带来的各种的维护问题,所以对于依赖库的管理的最佳实践模式 —— 建立一个单独的依赖配置文件,通过这个依赖配置文件定义所有需要用到的依赖,随后在 build.gradle 文件里面去通过这个依赖文件引入相应的依赖库,换言之,build.gradle 文件不直接参与任何版本的操作。

5.2 依赖文件

  • 在项目中定义有一个 dependencies.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. ]

10.png

5.2 配置引入

  • 修改 build.gradle 文件,引入以上的库文件:
  1. apply from :'dependencies.gradle' // 引入所有的依赖文件

5.3 依赖配置

  • 所有的依赖配置最终都是在 build.gradle 文件中完成的,修改在 build.gradle 文件中的 dependencies 中配置,内容如下:
  1. dependencies { // 依赖管理
  2. /* junit 5 */
  3. testImplementation( // 如果有多个依赖,使用 , 隔开
  4. libraries.'junit-jupiter'
  5. )
  6. /* druid */
  7. implementation( // 如果有多个依赖,使用 , 隔开
  8. libraries.'druid'
  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. repositories { // 仓库配置
  21. mavenCentral()
  22. }
  23. dependencies { // 依赖管理
  24. /* junit 5 */
  25. testImplementation( // 如果有多个依赖,使用 , 隔开
  26. libraries.'junit-jupiter'
  27. )
  28. /* druid */
  29. implementation( // 如果有多个依赖,使用 , 隔开
  30. libraries.'druid'
  31. )
  32. }
  33. tasks.withType(JavaCompile) { // 针对程序编译的任务进行配置
  34. options.encoding = "UTF-8"
  35. }
  36. def mainClassName = 'com.github.fairy.era.GradleMain' // 程序的主类名称
  37. jar {
  38. archivesBaseName = 'gradle' // 生成的 jar 文件名称,如果不写此名称则使用项目名称
  39. manifestContentCharset = 'UTF-8' // 设置整个文件的编码
  40. metadataCharset = 'UTF-8' // 元数据设置编码
  41. manifest {
  42. attributes 'Manifest-Version': getArchiveVersion().getOrNull(), // 程序版本号
  43. 'Main-Class': "${mainClassName}",// 程序主类名称
  44. 'Implementation-Title': 'hello-gradle',// 程序主类名称
  45. 'Implementation-Version': archiveVersion // 版本编号
  46. }
  47. into('lib') { // 将程序锁需要的第三方组件包配置到 lib 目录之中
  48. from configurations.compileClasspath
  49. }
  50. }
  51. test { // 进行测试任务的配置
  52. useJUnitPlatform() // 使用 Junit 平台
  53. }
  54. sourceSets { // 建立源代码的目录集合
  55. main {
  56. java {
  57. srcDirs = ['src/main/java']
  58. }
  59. resources {
  60. srcDirs = ['src/main/resources', 'src/main/config']
  61. }
  62. }
  63. }
  • 那么,此时的 Gradle 项目就可以通过一个专属的依赖文件进行所有依赖库的管理了,以后如果要维护版本只需要修改专属的依赖配置文件集合,不需要改动 build.gradle 文件了。