一、构建Java和JVM项目


// 1. Introduction 入门
对于Java项目,最简单的构建脚本就是应用Java Library Plugin ,并选择设置项目version,和选择使用Java toolchain

// example 1 应用Java Library Plugin
plugins {
id 'java-library'
}

java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}

version = '1.2.1'

使用Java Library Plugin,可以获得许多功能(task):
- compileJava: 编译所有在src/main/java路径的java源文件
- compileTestJava: 编译所有在src/test/java路径的java源文件
- test: 运行所有在src/test/java下的test
- jar: 将编译的类main和src/main/resources 打包成一个JAR包,并命名为<项目>-<版本>.jar
- javadoc: 对main类剩菜Javadoc

Java Library Plugin 将上述的任务集成到Base plugin lifeCycle task中
- jar 附上 assembly 即执行assembly时会先执行jar
- test 附上 check

// 2. 通过源集合声明源文件
gradle对java的支持引入一个新的概念:基于源代码构建的项目:source sets
主要的思想是源文件和资源通常是按类型进行逻辑分组,而每个逻辑组都有自己的文件依赖项,类路径等的集合。
最重要的是,构成源集的文件不必在同一目录下。

source sets 是一个强大的概念,其可以将编译的以下几方面联系在一起:
- 源文件及其位置
- 编译类路径,包括任何必须的依赖项
- 放置已编译的类文件的位置
![Java SourceSets编译](https://docs.gradle.org/current/userguide/img/java-sourcesets-compilation.png)

Java项目通常包含源文件以外的资源,这些资源可能需要处理并打包在最终JAR中。
Java Library Plugin 自动创建processSourceSetResources任务处理这些资源
![java资源集处理资源](https://docs.gradle.org/current/userguide/img/java-sourcesets-process-resources.png)

当然:Java Library Plugin 还定义了test source sets 代表 项目测试,用于运行test任务

// 3. 管理依赖
为Java项目添加依赖需要三点信息:
a. 项目需要哪个依赖,包括名称,版本等信息
b. 依赖需要什么,比如编译或运行
c. 从何处获得此依赖
a b 可以在dependencies{}块中指定。 c 在repositories{}块指定

//example 2 添加依赖
repositories {
mavenCentral()
}

dependencies {
implementation 'org.example.group:module-example:1.0.0'
}
// Repository : 寻找依赖的模块的来源
// Configuration : dependencies集合的命名
// Module coordinate : <group>:<module>:<version>'

对于configuration,主要有以下几点:
- compileOnly : 仅编译时需要,不属于运行时类路径一部分。
- implementation : 用于编译和运行时(常用)
- runtimeOnly : 仅运行时使用,不用于编译
- testCompileOnly : 等价于compileOnly,只是此用于test
- testImplementation : 同上
- testRuntimeOnly : 同上

并且,Java Library Plugin 还提供了两个额外的配置
- api , compileOnlyApi : 用于编译模块和依赖该模块的任何模块所需的依赖关系。

// 4. 编译代码
若要轻松编译生产代码和测试代码,需遵循以下约定:
1. 将生产源代码放在src / main / java目录下
2. 将您的测试源代码放在src / test / java下
3. 在compileOnly或implementation配置中声明您的生产编译依赖项
4. 在testCompileOnly或testImplementation配置中声明您的测试编译依赖项
5. 对生产代码运行compileJava和对测试任务运行compileTestJava

// a. 自定义文件和目录位置
每个source sets都定义源代码所在的位置,以及类文件的资源和输出目录。但可以自定义约定值
// example 3 声明自定义源目录 srcDirs
sourceSets {
main {
java {
srcDirs = ['src']
}
}
test {
java {
srcDirs = ['test']
}
}
}

// example 4 声明附加自定义源目录 srcDir
sourceSets {
main {
java {
srcDir = 'third/src/main/java'
}
}
}
// srcDir()来附加目录路径,sirDir属性将替换所有现有值

// b. 更改编译器选项

// examle 5
compileJava {
options.incemental = true
options.fork = true
options.failOnError = false
}

// c. 定位指定的Java版本
默认情况下,Gradle将Java代码编译为运行Gradle的JVM的语言级别
通过使用Java toolchains,您可以通过确保由构建定义的给定Java版本用于编译,执行和文档编制来断开该链接。

// d. 分别编译独立的源
大多数项目至少有两个独立的源集:生产代码和测试代码。Gradle已经将此场景作为其Java约定的一部分
但是,有时候需要自定义源集,比如进行某种形式的集成测试

// 5. 管理资源 resources
Java Library Plugin 会添加copy任务为每个源集,用于处理相关的resources
任务名约定为processSourceSetResources 或者processResources(为main类源集),自动复制src/[sourceSet]/resources到生产的Jar目录。同时该目录也会包含在tests的运行时路径中

// a. Java 属性文件和可复制的构建
可以通过WriteProperties任务轻松创建Java属性文件,Properties.store()即降低了增量构建的用处(减少相同输入输出不重复执行的情况)
即使使用相同的属性和值,用于编写属性文件的标准Java API也会每次生成一个唯一的文件,因为注释中包括了时间戳。WriteProperties如果所有属性均未更改,则Gradle的任务逐字节生成完全相同的输出
可以导致更好的增量构建集成,而且还有助于可复制的构建。因为不管在任何情况下,都可以在构建执行中得到相同的结果

// 6. 运行测试
除了提供自动化构建src/test/java的单元测试外,Java Library Plugin 提供本机运行Juint 和 TestNG,因此提供:
- 自动的test类型的test任务,使用test源集
- html 测试结果报告包括所有运行的test
- 轻松选择过滤要运行的测试
- 精细控制测试运行方式
- 可以自定义test 执行任务和 report生成任务

//下节会详细讲gradle test相关

// 7. 打包和发布
如何打包发布取决项目类型,包括Libraries, applications, web applications and enterprise applications
默认,Java Library Plugin使用 jar 任务打包所有编译的类和资源到一个Jar包。Jar包也会自动构建被assemble任务
如果需要打包Javadoc和源代码,可以使用javadocJar和sourcesJar任务

// exmple 7 配置一个项目去发布Javadoc和sources
java {
withJavadocJar()
withSourcesJar()
}

// example 8 创建一个超级Jar包
plugins {
id 'java'
}

version = '1.0.0'

repositories {
mavenCentral()
}

dependencies {
implementation 'commons-io:commons-io:2.6.0'
}

task uberJar(type: Jar) {
archiveClassifier = 'uber'

from sourceSets.main.output

dependsOn configurations.runtimeClasspath
from {
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect{ zipTree(it) }
}
}

// 8. 创建一个API文档
Java Library Plugin 提供一个Javadoc类型的javado任务用于生成标准的javadoc为所有的生产代码
// example 9 定义一个自定义Javadoc任务【为测试生产API文档】
task testJavadoc(type: Javadoc) {
source = sourceSets.test.allJava
}

// 9. 清除 build
Java Library Plugin 添加clean任务,可以简单删除$buildDir文件夹及内All。
当然,这个task只是Delete一个实例,也可以使用dir属性选择要clean的目标文件夹

二、在Java和Jvm项目中进行测试

Jvm上进行测试时很丰富的主题,有许多不同的测试库和框架。

// 1. 基础
所有JVM测试都围绕一种任务类型:Test。这将运行测试用例并整理结果。then,你可以使用TestReport任务实例将结果转换为报告

Test任务需要两点信息
1、 从何处可以找到已编译的测试类(Test.getTestClasserDirs())
2、 执行类路径,应包括:被测类及正使用的测试库(Test.getClasspath())

当使用JVM language plugin时,可以自动配置获得:
1、专用的test源集用于单元测试
2Test类型的test任务用于运行这些单元测试

// test 依附于 生命周期任务check。
test源集也需要创建相应的依赖关系配置。
大多数情况,仅需要配置适当的编译和运行时依赖项,并将所有必要的配置添加到test任务。

// example 1 :test task 的基本配置
dependencies {
testImplementation 'juint:junit:4.13'
}

test {
useJUnit()
maxHeapSize = '1G'
}

// 2. 测试执行
gradle在独立于主构建过程的单独(“分叉”)JVM中执行测试。并且可以使用与构建使用的JVM参数不同的参数运行测试。

Test任务的多个属性
- maxParallelForks : default:1, 可以设置此属性大于1,即可并行运行测试。但要确保测试相互隔离。(若需区分,可查看org.gradle.test.worker属性值)
- forkEvery : default:0, 此属性指定gradle在运行测试之前运行测试类和创建新测试的最大数量。目的在于管理leaky tests和框架的静态状态,这是是无法在测试中清除或重置的
- ignoreFailures : default: false, 若存在失败的测试,是否忽略,并继续项目构建
- failFast : default: false, 若希望在构建失败并在其测试失败后立即完成,则可设置为true。针对长期运行的测试,可以节省大量时间。若在所有测试运行前构建失败,测试报告仅包括已成功完成或未成功完成的测试报告。在命令行使用--fail-fast可以达到同样目的
- testLogging : default: not set, 用于控制记录哪些测试事件以及在什么级别进行记录。

// 3. 选择测试执行
只运行测试组件的子集的时候,gradle提供了两种机制:
- filtering (首选项)
- Test 包含/排除 【inclusion/exclusion】
过滤取代了包含/排除机制

* 使用gradle测试过滤,可以根据以下条件选择:
a. 完全限定的类名或完全限定的方法名。比如:org.gradle.SomeTest,org.gradle.SomeTest.someMethod
b. 如果模式以大写字母开头,则为简单的类名或方法名。 比如:SomeTest, SomeTest.someMethod
c. 使用通配符'*'匹配
命令行中可以使用 --tests选项进行启用筛选,其后可以添加1~多个选项

// example 2 : 在构建脚本中过滤测试
test {
filter {
// 包含任何测试中 指定的方法名
includeTestsMatching "*UiCheck"

// 包含package中的所有测试
includeTestsMatching "org.gradle.internal.*"

// 包含所有集成测试
includeTestsMatching "*IntegTest"
}
}

3.1 简单名称模式
Gradle将以大写字母开头的模式作为简单的类名或类名+方法名。
// example 3 : command execute
gradle test --tests SomeTestClass //执行SomeTestClass的所有测试
gradle test --tests SomeTestClass.someSpecificMethod // 执行SomeTestClass的someSpecificMethod方法
gradle test --tests SomeTestClass.*someMethod* //执行SomeTestClass方法名中有someMethod的测试

3.2 完全限定名称模式
如果模式不是以大写字母开头,则gradle识别为完全限定格式。
// example 4 : command execute
gradle test --tests org.gradle.SomeTestClass // 指定class
gradle test --tests org.gradle.SomeTestClass.someSpecificMethod // 指定方法
gradle test --tests "org.gradle.SomeTestClass.some method containing spaces" // 方法名带空格,需要对参数加引号
gradle test --tests 'all.in.specific.package*' // 在指定包内的所有class
gradle test --tests 'all.in.specific.package*.someSpecificMethod' // 在指定包内的指定方法
gradle test --tests '*IntegTest' // 所有包含IntegTest的类/方法
gradle test --tests '*IntegTest*ui*' // 格式同上
gradle test --tests '*ParameterizedTest.foo*' // 类包含ParameterizedTest字,方法包含foo的测试
gradle test --tests '*ParameterizedTest.*[2]' // 参数化测试的index是2的测试

通配符’*‘也包括‘.’,因此*.SomeTestClass将匹配任何程序包
可以将在命令行中定义的过滤器与连续构建结合使用,以在每次对生产或测试源文件进行更改后立即重新执行测试的子集。
gradle test --continuous --tests "com.mypackage.foo.*"

// 4. 测试报告
Test任务生成结果
a. HTML 测试报告
b. XML 测试结果,用于兼容Ant JUnit 报告任务,此任务可用于很多工具
c. 有效的二进制格式的结果,用于Test任务去生成其他格式文件

大多数情况下,可以获得标准的HTML报告,这是自动包含所有Test任务结果。(all)
项目级别的约定属性会影响测试报告。
// example 5 :更改测试报告和结果的目录
reporting.baseDir = "my-reports"
testResultsDirName = "$buildDir/my-test-results"

当然,若要自定义HTML测试报告,可以使用独立的TestReport任务,此任务仅需要destinationDir及要包含在报告中的测试结果
// example 6 :为子项目创建一个单元测试报告
// buildSrc/src/main/groovy/myproject.java-conventions.gradle

plugins {
id 'java'
}
// 禁止为单独子项目生成测试报告
test {
reports.html.enabled = false
}
// 将test report分享汇总到总项目
configurations {
binaryTestResultsElements { // test任务的二进制结果
canBeResolved = false
canBeConsumed = true
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION))
attribute(Category.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, 'test-report-data'))
}
outgoing.artifact(test.binaryResultsDirectory)
}
}

// build.gradle
// 用于收集测试报告数据的可解析配置
configurations {
testReportData {
canBeResolved = true
canBeConsumed = false
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION))
attribute(Category.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, 'test-report-data'))
}
}
}
dependencies {
testReportData project(':core')
testReportData project(':util')
}

tasks.register('testReport', testReport) {
destinationDir = file("$buildDir/reports/allTests")
// 使用来之testReportData配置的test结果
testResultDirs.from(configurations.testReportData)
}
// 分析:
a. 使用插件 myproject.java-conventions 将测试结果暴露给gradle
b. 在插件内声明一个consumable 配置: binaryTestResultsElements,代表测试任务的二进制结果
c. 在总项目中,声明testReportData配置并依赖于所有要汇总测试结果的子项目。gradle从子项目自动选择二进制测试结果。
d. 添加testReport任务,汇总来自testResultsDirs.from()的测试结果,其中也包含所有从testReportData配置解析的所有二进制测试结果。
// 注意:
TestReport类型任务是合并了多个测试任务的结果,因此很难区分该类的各个执行和其输出。

// 5. 测试检测(gradle如何检测到这些测试)
对于JUnit,gradle会扫描JUnit3和JUnit4的测试类,其条件为:
- 最终继承自TestCase或GroovyTestCase类
- 使用注解@RunWith
- 包含带有注解@Test的方法或超类

对于TestNG, Gradle扫描方式是:使用@Test的注解的方法

设置scanForTestClasses属性为false可以禁止检测测试。则需要使用includes/excludes属性去检测。若没有设置includes/excludes,则会默认去匹配"**/*Tests.class" and "**/*Test.class"

// 6. 测试分组
JUnit4.8引入的JUnit4的测试类和方法分组的类别概念,允许指定要includes/excludes的JUnit类

// example 7 JUnit分类 ,使用测试CategoryA,排除CategoryB
test {
useJUnit {
includeCategories 'org.gradle.junit.CategoryA'
excludeCategories 'org.gradle.junit.CategoryB'
}
}
JUnit Platform引入标签来替换类别,即可使用Test.useJUnitPlatform指定includes/excludes的标签

// example 8 JUnit Platform Tag (JUnit 5)
test {
useJUnitPlatform {
includeTags 'fast'
excludeTags 'slow'
}
}

TestNG使用测试组概念,即Test.useTestNG设置配置包括或排除
// example 9 TestNG 分组测试
test {
useTestNG {
excludeGroups 'integrationTests'
includeGroups 'unitTests'
}
}

// 7. 使用JUnit 5
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform 是在JVM启动测试框架基础。
JUnit Jupiter 是编程模型和扩展模型的组合,用于在JUnit 5编写和扩展测试。
JUnit Vintage 是提供一种TestEngine,以允许基于JUnit3或JUnit4的测试

// example 10 使用JUint Platform 运行测试
test {
useJUnitPlatform()
}

编译和执行JUnit Jupiter测试
若要在gradle中启用JUnit Jupiter支持,需要添加以下依赖项:
// example 11 添加JUnit Jupiter依赖(在springboot项目中,springboot test依赖包含了Jupiter)
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}

使用JUint Vintage执行旧版本测试
若要在JUnit Platforn运行JUnit3/4测试,则需要添加额外的JUnit Vintage Engine依赖项
// example 12 : 添加JUnit Vintage Engine依赖项
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
// vintage
testCompileOnly 'junit:junit:4.13'
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'
}

JUnit Platform允许您使用不同的测试引擎JUnit当前提供了两种TestEngine开箱即用的实现: junit-jupiter-engine和junit-vintage-engine。
若需要显示选择特定的测试引擎,可以添加设置
// example 13: 选择特定测试引擎
test {
useJUnitPlatform {
includeEngines 'junit-vintage'
}
}

// 8. 配置集成测试
项目的常见要求是以一种或另一种形式合并集成测试。将集成测试添加到构建的步骤:
a. 为集成测试创建一个source sets
b. 将所需依赖项添加到源集的配置中
c. 为该源集配置编译和运行时路径
d. 创建任务以运行集成测试

// example 14 : 设置集成测试的配置(a b c三步,使用intTest)
sourceSets {
intTest {
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
}
}
configurations {
intTestImplementation.extendsFrom implementation
intTestRuntimeOnly.extendsFrom runtimeOnly
}
dependencies {
intTestImplementation 'junit:junit:4.13'
}
依据此示例分析,这将配置一个新源集,intTest,并自动创建:
- intTestImplementation,intTestRuntimeOnly,intTestCompileOnly配置
- compileIntTestJava 任务,将编译src/intTest/java的源文件
并且注意:
- sourceSets.main.output是包含编译的生产类和资源的所有目录的文件集合,将main源集中的生产类添加到集成测试的编译和运行时类路径中。
- intTestImplementation/intTestRuntimeOnly 配置继承于 implementation/runtimeOnly,这代表,所有在生产代码声明的依赖项也将成为继承测试的依赖项
- +=允许您向其添加路径和路径集合

创建和配置源***自动设置编译阶段,但对于运行集成测试没有任何作用。故而需要设定一个测试任务,该任务来源于新源集,并配置运行类路径和测试类
// example 15: 定义一个集成测试任务
task integrationTest(type: Test) {
description = 'Runs integration tests.'
group = 'verification'

testClassesDirs = sourceSets.intTest.output.classesDirs // 已编译测试类的位置
classpath = sourceSets.intTest.runtimeClasspath //运行时路径
shouldRunAfter test // 集成测试运行较慢,因此设置在单元测试之后运行
}
check.dependsOn integrationTest

// 9. 跳过测试
若要运行构建时跳过测试,可以使用命令行参数或在构建脚本中设置。
- 命令行参数操作:gradle build -x {testName} 或者 gradle build --exclude-test {testName}
- 构建脚本中可以通过Task.onlyIf()方法使测试有条件执行。
// example 16 : 跳过项目中有指定属性的单元测试
test.onlyIf { !project.hasProperty('mySkipTests') }

// 10. 强制运行测试
通过清除相关Test任务的输出,并在这种情况下再次运行测试来强制测试运行.cleanTest基于基础插件提供的任务规则。您可以将其用于任何任务。
gradle cleanTest {testName}

11. 运行测试时进行调试
- Test.getDebug()设置为true或者命令行使用--debug-jvm选项,测试调试启动时,gradle会监听5005端口
- 也可以在DSL启用调试
// example 17
test {
debugOptions {
enabled = true
port = 4455 //监听端口
server = true
suspend = true
}
}

三、JVM 项目的工具链

Java工具链是一组工具,通常取自本地JRE / JDK安装,用于配置构建的不同方面。编译任务可以javac用作其编译器,而test和exec任务可以使用该java命令,同时javadoc将用于生成文档。
默认情况下,Gradle使用相同Java版本运行gradle自身和构建JVM项目。但有些情况需要指定不同Java版本

1. 消费工具链
构建可以通过声明所需的Java语言版本以及供应商(可选)来全局定义其目标的工具链
// example 1 :指定java语音版本
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
分析:此任务将执行:
a. 设置所有编译、测试、Javadoc任务使用定义的工具链(可能与gradle本身使用的不同)
b. Gradle检测本地按照的JVM
c. Gradle选择符合构建要求的JRE/JDK
d. 若找不到,将自动从AdoptOpenJDK下载

若需要指定工具链的vendor,JvmVendorSpec类中列举一些vendor可以使用
// example 2 :指定工具链的vendor
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.ADOPTOPENJDK // 指定已知的vendor
//若vendor不是已知的,可以使用匹配字符串方式设定vendor
// vendor = JvmVendorSpec.matching("customString")
}
}

使用虚拟机implementation选择工具链
implementation 两种参数选择: VENDOR_SPECIFIC、J9(使用OpenJ9/IBMJ9 运行引擎)
// example 3 :使用虚拟机implementation选择工具链
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.ADOPTOPENJDK
implementation = JvmImplementation.J9
}
}

2. 为单任务指定自定义工具链
如果需要指定特定任务的工具链,可以指定任务使用的确切工具。比如,Test任务的JavaLauncher属性定义用于启动测试的Java可执行文件
// example 4:全局配置JDK8,指定的test任务配置JDK14
tasks.withType(JavaCompile).configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(8)
}
}
task('testOn14', type: Test) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(14)
}
}

在application子项目,添加Java执行任务使用JDK14运行
task('runOn14', type: JavaExec) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(14)
}
// 运行时路径
classpath = sourceSets.main.runtimeClasspath
// main类路径
mainClass = application.mainClass
}

三类有效工具:
- JavaCompiler : 用于JavaCompile任务
- JavaLauncher : 用于JavaExec或Test任务
- JavadocTool : 用于Javadoc任务

3. 常用配置操作

默认情况下,Gradle自动检测本地JRE / JDK安装,若需要关闭自动检测,则可以:
- 启动gradle时使用 -Porg.gradle.java.installations.auto-detect=false
- 在gradle.properties中设置org.gradel.java.installations.auto-detect=false

默认情况下,Gradle会从AdoptOpenJDK API确定和下载匹配的JDK,若要关闭自动配置
- 启动gradle时使用 -Porg.gradle.java.installations.auto-download=false
- 在gradle.properties中设置org.gradel.java.installations.auto-download=false

自定义工具链的位置,属性
- org.gradle.java.installations.fromEnv = JDK8,JRE14 //环境变量
- org.gradle.java.installations.paths = / custom / path / jdk1.8,/ shared / jre11 // 安装路径

四、 管理JVM项目的依赖关系

1. 剖析典型的构建脚本
// example 1 :基于JVM的项目的依赖项声明
plugins {
id 'java-library'
}
repositories {
mavenCentral()
}
dependencies {
// 声明Hibernate-core3.6.7.Final需要参与编译运行该项目生产的源代码
implementation 'org.hibernate:hibernate-core:3.6.7.Final'
// 从java库要引入 guava
api 'com.google.guava:guava:23.0'
// 编译运行测试项目,需要依赖junit4+版本,即版本大于等于4.0
testImplementation 'junit:junit:4.+'
}

2. 模块依赖
最常见的是模块依赖,还有文件依赖,项目依赖等。而模块通常存储在存储库中,比如Maven mavenCentral
// example 2 : 定义模块依赖关系
dependencies {
implementation 'org.hibernate.hibernate-core:3.6.7.Final'
}

3. 使用依赖配置
配置是一组依赖和组件的命名,其有三个目的:
a. 声明依赖关系 :声明在执行插件定义的任务期间出于各种目的还需要其他哪些子项目或外部工件。
b. 解析依赖 : 插件使用配置来查找/下载其定义的任务的输入。
c. 暴露组件以供使用 :插件使用配置来定义它生成供其他项目使用的组件

Java Library Plugin常用依赖配置
a. implementation : 编译项目生产源集的依赖关系,运行时也向使用方公开。但不是项目公开API的一部分
b. api : 用来编译生产源集的依赖关系,并且是由项目暴露出的API的一部分 (依赖可以传递至上层module)
c. compileOnly : 编译时需要的依赖项,而在运行时则不需要。
d. runtimeOnly : 仅在运行时才需要的依赖关系
e. compileOnlyApi : 声明模块和使用者在编译时需要的依赖关系,而在运行时则不需要。
f. testImplementation : 编译和运行项目的测试源所需的依赖项。
g. testCompileOnly/testRuntimeOnly :用于测试源集,同生产代码功能

4. 声明通用的Java存储库
Gradle在存储库可以查找外部依赖文件Gradle支持不同存储库类型,比如Maven和Ivy,也支持通过HTTP或其他协议访问存储库的方式
默认,Gradle不定义任何存储库。因此需要使用Project.repositories{}定义,当然,也可以定义多个存储库,gradle将按定义顺序查找依赖包,查找到第一个则停止
// example 3 : maven central 使用
repositories {
mavenCentral()
}
// example 4 : 本地Ivy目录使用
repositories {
ivy {
url "../local-repo"
}
}