使用库构建Java应用程序示例
您可以在支持Gradle的IDE中打开此示例。 |
为了让您的软件项目为增长做好准备,您可以将Gradle项目组织成多个子项目,以模块化您正在构建的软件。在本指南中,您将学习如何以Java应用程序为例来构建此类项目。但是,一般概念适用于您使用Gradle构建的任何软件。您可以按照本指南的步骤从头开始创建一个新项目,或使用上面的链接下载完整的示例项目。
您将构建什么
您将构建一个由一个应用程序和多个库项目组成的Java应用程序。
您需要什么
-
一个文本编辑器或 IDE - 例如 IntelliJ IDEA
-
Java Development Kit (JDK),版本 8 或更高版本 - 例如 AdoptOpenJDK
-
最新 Gradle 发布版
创建项目文件夹
Gradle 带有一个内置任务 init
,用于在空文件夹中初始化一个新的 Gradle 项目。init
任务使用(也内置的)wrapper
任务来创建一个 Gradle wrapper 脚本 gradlew
。
第一步是为新项目创建一个文件夹并进入该文件夹。
$ mkdir demo $ cd demo
运行 init 任务
在新项目目录下,在终端中使用以下命令运行init
任务:gradle init
。当出现提示时,选择1: application
项目类型和1: Java
作为实现语言。然后,选择2: Application and library project
。接下来,您可以选择用于编写构建脚本的DSL——1 : Kotlin
或2: Groovy
。对于其他问题,按Enter键使用默认值。
输出将如下所示
$ gradle init Select type of build to generate: 1: Application 2: Library 3: Gradle plugin 4: Basic (build structure only) Enter selection (default: Application) [1..4] 1 Select implementation language: 1: Java 2: Kotlin 3: Groovy 4: Scala 5: C++ 6: Swift Enter selection (default: Java) [1..6] 1 Project name (default: demo): Enter target Java version (min: 7, default: 21): Select application structure: 1: Single application project 2: Application and library project Enter selection (default: Single application project) [1..2] 2 Select build script DSL: 1: Kotlin 2: Groovy Enter selection (default: Kotlin) [1..2] Select test framework: 1: JUnit 4 2: TestNG 3: Spock 4: JUnit Jupiter Enter selection (default: JUnit Jupiter) [1..4] Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] BUILD SUCCESSFUL 1 actionable task: 1 executed
init
任务生成的新项目结构如下
├── gradle (1)
│ ├── libs.versions.toml (2)
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew (3)
├── gradlew.bat (3)
├── settings.gradle.kts (4)
├── buildSrc
│ ├── build.gradle.kts (5)
│ ├── settings.gradle.kts (5)
│ └── src
│ └── main
│ └── kotlin (6)
│ ├── buildlogic.java-application-conventions.gradle.kts
│ ├── buildlogic.java-common-conventions.gradle.kts
│ └── buildlogic.java-library-conventions.gradle.kts
├── app
│ ├── build.gradle.kts (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── app
│ │ ├── App.java
│ │ └── MessageUtils.java
│ └── test (9)
│ └── java
│ └── demo
│ └── app
│ └── MessageUtilsTest.java
├── list
│ ├── build.gradle.kts (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── list
│ │ └── LinkedList.java
│ └── test (9)
│ └── java
│ └── demo
│ └── list
│ └── LinkedListTest.java
└── utilities
├── build.gradle.kts (7)
└── src
└── main (8)
└── java
└── demo
└── utilities
├── JoinUtils.java
├── SplitUtils.java
└── StringUtils.java
├── gradle (1)
│ ├── libs.versions.toml (2)
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew (3)
├── gradlew.bat (3)
├── settings.gradle (4)
├── buildSrc
│ ├── build.gradle (5)
│ ├── settings.gradle (5)
│ └── src
│ └── main
│ └── groovy (6)
│ ├── buildlogic.java-application-conventions.gradle
│ ├── buildlogic.java-common-conventions.gradle
│ └── buildlogic.java-library-conventions.gradle
├── app
│ ├── build.gradle (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── app
│ │ ├── App.java
│ │ └── MessageUtils.java
│ └── test (9)
│ └── java
│ └── demo
│ └── app
│ └── MessageUtilsTest.java
├── list
│ ├── build.gradle (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── list
│ │ └── LinkedList.java
│ └── test (9)
│ └── java
│ └── demo
│ └── list
│ └── LinkedListTest.java
└── utilities
├── build.gradle (7)
└── src
└── main (8)
└── java
└── demo
└── utilities
├── JoinUtils.java
├── SplitUtils.java
└── StringUtils.java
1 | 为包装器文件生成的文件夹 |
2 | 生成的版本目录 |
3 | Gradle 包装器启动脚本 |
4 | 定义构建名称和子项目的设置文件 |
5 | buildSrc 的构建脚本,用于配置构建逻辑的依赖项 |
6 | 用 Groovy 或 Kotlin DSL 编写的约定插件的源文件夹 |
7 | 三个子项目(app 、list 和 utilities )的构建脚本 |
8 | 每个子项目中的Java源文件夹 |
9 | 子项目中的Java测试源文件夹 |
您现在已经设置好项目,可以构建一个模块化为多个子项目的Java应用程序。
审查项目文件
settings.gradle(.kts)
文件有两行值得注意
rootProject.name = "demo"
include("app", "list", "utilities")
rootProject.name = 'demo'
include('app', 'list', 'utilities')
-
rootProject.name
为构建分配一个名称,这会覆盖根据其所在目录命名构建的默认行为。建议设置一个固定名称,因为如果项目被共享(例如,作为Git仓库的根),文件夹可能会更改。 -
include("app", "list", "utilities")
定义构建由相应文件夹中的三个子项目组成。可以通过扩展列表或添加更多include(…)
语句来添加更多子项目。
由于我们的构建由多个子项目组成,我们希望在它们之间共享构建逻辑和配置。为此,我们利用了位于buildSrc
文件夹中的所谓约定插件。buildSrc
中的约定插件是利用Gradle插件系统编写可重用构建配置位的简单方法。
在此示例中,我们可以找到三个基于彼此的约定插件
plugins {
java (1)
}
repositories {
mavenCentral() (2)
}
dependencies {
constraints {
implementation("org.apache.commons:commons-text:1.13.0") (3)
}
testImplementation("org.junit.jupiter:junit-jupiter:5.12.1") (4)
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
tasks.named<Test>("test") {
useJUnitPlatform() (5)
}
plugins {
id 'java' (1)
}
repositories {
mavenCentral() (2)
}
dependencies {
constraints {
implementation 'org.apache.commons:commons-text:1.13.0' (3)
}
testImplementation 'org.junit.jupiter:junit-jupiter:5.12.1' (4)
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform() (5)
}
java-common-conventions
定义了一些应由我们所有Java项目共享的配置——无论它们代表库还是实际应用程序。首先,我们应用Java插件 (1) 以获得所有构建Java项目的功能。然后,我们声明一个仓库——mavenCentral()
——作为外部依赖项的来源 (2),定义依赖项约束 (3) 以及所有子项目共享的标准依赖项,并将JUnit 5设置为测试框架 (4…)。其他共享设置,如编译器标志或JVM版本兼容性,也可以在此处设置。
plugins {
id("buildlogic.java-common-conventions") (1)
`java-library` (2)
}
plugins {
id 'buildlogic.java-common-conventions' (1)
id 'java-library' (2)
}
plugins {
id("buildlogic.java-common-conventions") (1)
application (2)
}
plugins {
id 'buildlogic.java-common-conventions' (1)
id 'application' (2)
}
java-library-conventions
和java-application-conventions
都应用了java-common-conventions
插件(1),以便库和应用程序项目都可以共享在该插件中执行的配置。接下来,它们分别应用java-library
或application
插件(2),从而将我们的通用配置逻辑与库或应用程序的特定功能结合起来。虽然此示例中没有更细粒度的配置,但库或应用程序项目特定的构建配置可以放入这些约定插件脚本之一中。
让我们看看子项目中的 build.gradle(.kts)
文件。
plugins {
id("buildlogic.java-application-conventions")
}
dependencies {
implementation("org.apache.commons:commons-text")
implementation(project(":utilities"))
}
application {
mainClass = "demo.app.App" (1)
}
plugins {
id 'buildlogic.java-application-conventions'
}
dependencies {
implementation 'org.apache.commons:commons-text'
implementation project(':utilities')
}
application {
mainClass = 'demo.app.App' (1)
}
plugins {
id("buildlogic.java-library-conventions")
}
plugins {
id 'buildlogic.java-library-conventions'
}
plugins {
id("buildlogic.java-library-conventions")
}
dependencies {
api(project(":list"))
}
plugins {
id 'buildlogic.java-library-conventions'
}
dependencies {
api project(':list')
}
查看构建脚本,我们可以看到它们最多包含三个块
-
每个构建脚本都应该有一个
plugins {}
块来应用插件。在一个结构良好的构建中,它可能只应用一个约定插件,如本例所示。约定插件将负责应用和配置核心Gradle插件(如application
或java-library
)、其他约定插件或来自插件门户的社区插件。 -
其次,如果项目有依赖项,则应添加一个
dependencies {}
块。依赖项可以是外部的,例如我们在java-common-conventions
中添加的JUnit依赖项,也可以指向其他本地子项目。为此,使用project(…)
表示法。在我们的示例中,utilities
库需要list
库。而app
则使用utilities
库。如果本地项目相互依赖,Gradle会在需要时(并且仅在需要时)负责构建依赖项目。要了解更多信息,请查阅有关Gradle中的依赖管理的文档。 -
第三,可能有一个或多个插件的配置块。这些配置块只有在直接配置特定于某个项目的某些内容时才应在构建脚本中直接使用。否则,此类配置也应属于约定插件。在此示例中,我们使用
application {}
块,该块特定于application
插件,将app
项目中的mainClass
设置为demo.app.App
(1)。
我们拥有的最后一个构建文件是 buildSrc
中的 build.gradle(.kts)
文件。
plugins {
`kotlin-dsl` (1)
}
repositories {
gradlePluginPortal() (2)
}
plugins {
id 'groovy-gradle-plugin' (1)
}
repositories {
gradlePluginPortal() (2)
}
此文件为构建约定插件本身奠定了基础。通过应用插件开发插件之一——groovy-gradle-plugin
或kotlin-dsl
——(1) 我们支持将约定插件作为构建文件写入buildSrc
。这些就是我们上面已经检查过的约定插件。此外,我们添加了Gradle的插件门户作为仓库(2),这使我们能够访问社区插件。要使用插件,需要将其声明为dependencies {}
块中的依赖项。
除了Gradle构建文件,您还可以在相应的文件夹中找到Java源代码和测试源代码示例。您可以随意修改这些生成的源代码和测试,以探索Gradle在按后续描述运行构建时如何响应更改。
运行测试
您可以使用./gradlew check
执行所有子项目中的所有测试。当您使用简单的任务名称(如check
)调用Gradle时,该任务将为所有提供它的子项目执行。要仅针对特定子项目,您可以使用任务的完整路径。例如,:app:check
将只执行app
项目的测试。但是,在此示例中,其他子项目仍将被编译,因为app
声明了对它们的依赖。
$ ./gradlew check BUILD SUCCESSFUL 9 actionable tasks: 9 executed
如果所有测试都成功通过,Gradle不会向控制台打印更多输出。您可以在<子项目>/build/reports
文件夹中找到测试报告。您可以随意更改一些示例代码或测试,然后重新运行check
,看看如果测试失败会发生什么。
运行应用程序
多亏了 application
插件,您可以直接从命令行运行应用程序。run
任务告诉 Gradle 执行分配给 mainClass
属性的类中的 main
方法。
$ ./gradlew run > Task :app:run Hello world! BUILD SUCCESSFUL 2 actionable tasks: 2 executed
首次运行 wrapper 脚本 gradlew 时,可能需要一些延迟,因为该版本的 gradle 会被下载并本地存储在您的 ~/.gradle/wrapper/dists 文件夹中。 |
捆绑应用程序
application
插件还会为您捆绑应用程序及其所有依赖项。存档还将包含一个脚本,用于通过一个命令启动应用程序。
$ ./gradlew build BUILD SUCCESSFUL in 0s 7 actionable tasks: 7 executed
如果您运行如上所示的完整构建,Gradle 将为您生成两种格式的存档:app/build/distributions/app.tar
和 app/build/distributions/app.zip
。
发布构建扫描
了解您的构建在幕后做什么的最佳方法是发布 构建扫描。为此,只需使用 --scan
标志运行 Gradle 即可。
$ ./gradlew build --scan BUILD SUCCESSFUL in 0s 7 actionable tasks: 7 executed Publishing a Build Scan to scans.gradle.com requires accepting the Gradle Terms of Service defined at https://gradle.com/terms-of-service. Do you accept these terms? [yes, no] yes Gradle Terms of Service accepted. Publishing Build Scan... https://gradle.com/s/5u4w3gxeurtd2
点击链接,探索执行了哪些任务,下载了哪些依赖项以及更多详细信息!
总结
就这样!您现在已成功使用Gradle配置和构建了一个Java应用程序项目。您已学会如何
-
初始化一个生成Java应用程序的项目
-
通过组合多个子项目来创建模块化软件项目
-
使用
buildSrc
中的约定插件在子项目之间共享构建配置逻辑 -
在所有子项目中运行同名任务
-
在特定子项目中运行任务
-
构建、捆绑和运行应用程序
后续步骤
随着您的项目增长,您可能对如何配置 JVM 项目、构建多项目构建和依赖管理的更多详细信息感兴趣