使用库构建 Scala 应用程序示例
您可以使用 IntelliJ 原生导入器 或 Eclipse Buildship 在 IDE 中打开此示例。 |
为了使您的软件项目能够扩展,您可以将 Gradle 项目组织成多个子项目,以模块化您正在构建的软件。在本指南中,您将学习如何以 Scala 应用程序为例构建这样的项目。但是,这些通用概念适用于您使用 Gradle 构建的任何软件。您可以按照本指南逐步创建新的项目,也可以使用上面的链接下载完整的示例项目。
您将构建的内容
您将构建一个由一个应用程序和多个库项目组成的 Scala 应用程序。
您需要什么
-
一个文本编辑器或 IDE - 例如 IntelliJ IDEA
-
Java 开发工具包 (JDK),版本 8 或更高 - 例如 AdoptOpenJDK
-
最新的 Gradle 发行版
创建项目文件夹
Gradle 带有一个内置任务,称为 init
,它在空文件夹中初始化一个新的 Gradle 项目。init
任务使用(也是内置的)wrapper
任务来创建一个 Gradle 包装器脚本,gradlew
。
第一步是为新项目创建一个文件夹,并更改到该文件夹。
$ mkdir demo $ cd demo
运行 init 任务
在新的项目目录中,使用以下命令在终端中运行 init
任务:gradle init
。出现提示时,选择 1: application
项目类型和 4: Scala
作为实现语言。之后,选择 2: Add library projects
。接下来,您可以选择用于编写构建脚本的 DSL - 1 : Groovy
或 2: Kotlin
。对于其他问题,按回车键使用默认值。
输出将如下所示
$ gradle init Select type of project to generate: 1: basic 2: application 3: library 4: Gradle plugin Enter selection (default: basic) [1..4] 1 Split functionality across multiple subprojects?: 1: no - only one application project 2: yes - application and library projects Enter selection (default: no - only one application project) [1..2] 2 Select implementation language: 1: C++ 2: Groovy 3: Java 4: Kotlin 5: Scala 6: Swift Enter selection (default: Java) [1..6] 4 Select build script DSL: 1: Groovy 2: Kotlin Enter selection (default: Groovy) [1..2] 1 Project name (default: demo): Source package (default: demo): BUILD SUCCESSFUL 2 actionable tasks: 2 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.scala-application-conventions.gradle.kts
│ ├── buildlogic.scala-common-conventions.gradle.kts
│ └── buildlogic.scala-library-conventions.gradle.kts
├── app
│ ├── build.gradle.kts (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── app
│ │ ├── App.java
│ │ └── MessageUtils.scala
│ └── test (9)
│ └── java
│ └── demo
│ └── app
│ └── MessageUtilsTest.scala
├── list
│ ├── build.gradle.kts (7)
│ └── src
│ ├── main (8)
│ │ └── java
│ │ └── demo
│ │ └── list
│ │ └── LinkedList.scala
│ └── test (9)
│ └── java
│ └── demo
│ └── list
│ └── LinkedListTest.scala
└── utilities
├── build.gradle.kts (7)
└── src
└── main (8)
└── java
└── demo
└── utilities
├── JoinUtils.scala
├── SplitUtils.scala
└── StringUtils.scala
├── 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.scala-application-conventions.gradle
│ ├── buildlogic.scala-common-conventions.gradle
│ └── buildlogic.scala-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 | 每个子项目中的 Scala 源文件夹 |
9 | 子项目中的 Scala 测试源文件夹 |
您现在已经设置了项目,可以构建一个模块化为多个子项目的 Scala 应用程序。
查看项目文件
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 {
scala (1)
}
repositories {
mavenCentral() (2)
}
dependencies {
constraints {
implementation("org.apache.commons:commons-text:1.11.0") (3)
implementation("org.scala-lang:scala-library:2.13.12")
}
implementation("org.scala-lang:scala-library") (4)
testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") (5)
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
tasks.named<Test>("test") {
useJUnitPlatform() (6)
}
plugins {
id 'scala' (1)
}
repositories {
mavenCentral() (2)
}
dependencies {
constraints {
implementation 'org.apache.commons:commons-text:1.11.0' (3)
implementation 'org.scala-lang:scala-library:2.13.12'
}
implementation 'org.scala-lang:scala-library' (4)
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1' (5)
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform() (6)
}
scala-common-conventions
定义了一些所有 Scala 项目应该共享的配置,无论它们是库还是实际的应用程序。首先,我们应用了 Scala 插件 (1),以便可以使用构建 Scala 项目的所有功能。然后,我们声明一个仓库 - mavenCentral()
- 作为外部依赖项的来源 (2),定义依赖项约束 (3) 以及所有子项目共享的标准依赖项,并将 JUnit 5 设置为测试框架 (4…)。其他共享设置,例如编译器标志或 JVM 版本兼容性,也可以在这里设置。
plugins {
id("buildlogic.scala-common-conventions") (1)
`java-library` (2)
}
plugins {
id 'buildlogic.scala-common-conventions' (1)
id 'java-library' (2)
}
plugins {
id("buildlogic.scala-common-conventions") (1)
application (2)
}
plugins {
id 'buildlogic.scala-common-conventions' (1)
id 'application' (2)
}
scala-library-conventions
和 scala-application-conventions
都应用了 scala-common-conventions
插件 (1),以便在那里执行的配置由库和应用程序项目共享。接下来,它们分别应用 java-library
或 application
插件 (2),从而将我们的通用配置逻辑与库或应用程序的具体内容结合起来。虽然在这个示例中没有更细粒度的配置,但库或应用程序项目特定的构建配置可以进入其中一个约定插件脚本。
让我们看一下子项目中的 build.gradle(.kts)
文件。
plugins {
id("buildlogic.scala-application-conventions")
}
dependencies {
implementation("org.apache.commons:commons-text")
implementation(project(":utilities"))
}
application {
mainClass = "demo.app.App" (1)
}
plugins {
id 'buildlogic.scala-application-conventions'
}
dependencies {
implementation 'org.apache.commons:commons-text'
implementation project(':utilities')
}
application {
mainClass = 'demo.app.App' (1)
}
plugins {
id("buildlogic.scala-library-conventions")
}
plugins {
id 'buildlogic.scala-library-conventions'
}
plugins {
id("buildlogic.scala-library-conventions")
}
dependencies {
api(project(":list"))
}
plugins {
id 'buildlogic.scala-library-conventions'
}
dependencies {
api project(':list')
}
查看构建脚本,我们可以看到它们包含多达三个块。
-
每个构建脚本都应该有一个
plugins {}
块来应用插件。在一个结构良好的构建中,它可能只应用一个约定插件,如本示例所示。约定插件将负责应用和配置核心 Gradle 插件(如application
或java-library
)其他约定插件或来自插件门户的社区插件。 -
其次,如果项目有依赖项,则应添加一个
dependencies {}
块。依赖项可以是外部的,例如我们在scala-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 构建文件之外,您还可以在相应的文件夹中找到示例 Scala 源代码和测试源代码。随意修改这些生成的源代码和测试,以探索 Gradle 如何在运行构建时对更改做出反应,如下一节所述。
运行测试
您可以使用./gradlew check
来执行所有子项目中的所有测试。当您使用简单的任务名称(如check
)调用 Gradle 时,该任务将在提供该任务的所有子项目中执行。要仅针对特定子项目,可以使用该任务的完整路径。例如,:app:check
将仅执行app
项目的测试。但是,在此示例中,其他子项目仍将被编译,因为app
声明了对它们的依赖项。
$ ./gradlew check BUILD SUCCESSFUL 9 actionable tasks: 9 executed
如果所有测试都成功通过,Gradle 不会在控制台中打印更多输出。您可以在<subproject>/build/reports
文件夹中找到测试报告。随意更改一些示例代码或测试,然后重新运行check
以查看如果测试失败会发生什么。
运行应用程序
借助 application
插件,您可以直接从命令行运行应用程序。run
任务告诉 Gradle 执行分配给 mainClass
属性的类中的 main
方法。
$ ./gradlew run > Task :app:run Hello world! BUILD SUCCESSFUL 2 actionable tasks: 2 executed
第一次运行包装脚本 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 配置和构建 Scala 应用程序项目。您已经了解了如何
-
初始化一个生成 Scala 应用程序的项目
-
通过组合多个子项目来创建模块化软件项目
-
使用
buildSrc
中的约定插件在子项目之间共享构建配置逻辑 -
在所有子项目中运行名称相似的任务
-
在特定子项目中运行任务
-
构建、打包和运行应用程序
下一步
当您的项目发展壮大时,您可能对如何配置 JVM 项目、构建多项目结构以及依赖项管理的更多详细信息感兴趣