Spring Initializr 文档
本节简要概述了 Spring Initializr 参考文档:可以将其视为本文档其余部分的地图。有些部分针对特定受众,因此本参考指南不适合线性阅读。
Spring Initializr 提供了一个可扩展的 API,用于生成基于 JVM 的项目,并检查用于生成项目的元数据,例如列出可用的依赖项和版本。
本文档大致分为三个部分
您可以使用 Spring Initializr 轻松创建您自己的实例,只需将 jar 作为库用于您自己的应用程序中。所需代码量极少,并且该服务具有非常丰富的配置结构,允许您不仅定义各种项目属性的值,还可以定义依赖项列表以及要应用于它们的约束。如果这听起来有趣,那么配置指南包含您需要的所有详细信息。您可能只想修改现有的 Spring Initializr 实例,例如添加新的依赖项类型,或更新现有依赖项的版本。对于这些以及其他简单常见的用例,请查看“操作指南”。
Spring Initializr 还提供了一个可扩展的 API,用于生成基于 JVM 的项目,并检查用于生成项目的元数据,例如列出可用的依赖项和版本。该 API 可以独立使用,也可以嵌入到其他工具中(例如,它被用于主要的 IDE 中,如 Spring Tool Suite、IntelliJ IDEA Ultimate,Netbeans 和 VSCode)。这些特性在API 指南中有所介绍。
1. 关于文档
Spring Initializr 参考指南以HTML格式提供。最新版本可在以下地址获取:docs.spring.io/initializr/docs/current/reference/html。
本文档的副本可供您自己使用或分发给他人,前提是您不对这些副本收取任何费用,并且无论以印刷版还是电子版形式分发,每个副本都包含本版权声明。
2. 获取帮助
使用 Spring Initializr 遇到问题了吗?我们很乐意提供帮助!
-
在 Gitter 上提问。
-
在 github.com/spring-io/initializr/issues 报告 Spring Initializr 的错误。
Spring Initializr 包括文档在内都是开源的!如果您发现文档有问题;或者只是想改进它们,请参与贡献。 |
引言
这是对 Spring Initializr 能够做什么的初步介绍。您将了解与 Spring Initializr 服务交互的各种方式,并更深入地了解它的功能。
该服务允许您快速生成基于 JVM 的项目。您可以定制要生成的项目:构建系统和打包、语言、坐标、平台版本,以及最后要添加到项目的依赖项。
4. Web 端点
该库可用于 Web 应用程序中,以暴露一些用于处理项目生成的端点。服务的主要入口点是其元数据端点,位于上下文的根路径。各种客户端使用它来确定可用的选项,并在可能的情况下将其呈现给用户。
元数据端点还列出了可以生成的项目类型以及服务如何触发它们。
5. 支持的客户端
开箱即用地,自定义实例使用 cURL
或 HTTPie
处理命令行请求。Spring Initializr 还支持各种 IDE,请查看您最喜欢的 IDE 文档以获取更多详细信息。
Spring Initializr 不提供 Web UI 来与服务交互。 |
配置指南
您可以使用 Spring Initializr 创建您自己的服务,该服务可以生成 JVM 项目。本节描述了如何创建和根据您的需求调整您自己的服务,以及如何配置现有服务。
6. 项目生成概述
在深入了解创建您自己的服务之前,我们先来看看项目生成的核心概念以及该库是如何构建来支持它们的。
Initializr 分为多个模块
-
initializr-actuator
:可选模块,提供关于项目生成的附加信息和统计数据。 -
initializr-bom
:提供了物料清单(Bill of Materials),以便在您的项目中更轻松地进行依赖管理。 -
initializr-docs
:文档。 -
initializr-generator
:核心项目生成库。 -
initializr-generator-spring
:可选模块,定义典型 Spring Boot 项目的约定。可以重用或替换为您自己的约定。 -
initializr-generator-test
:用于项目生成的测试基础设施。 -
initializr-metadata
:用于项目各个方面的元数据基础设施。 -
initializr-service-sample
:展示了一个基本的自定义实例。 -
initializr-version-resolver
:可选模块,用于从任意 POM 中提取版本号。 -
initializr-web
:为第三方客户端提供的 Web 端点。
为了理解项目生成背后的概念,让我们更详细地看看 initializr-generator
和 initializr-generator-spring
。
6.1. Initializr 生成器
initializr-generator
模块包含了生成基于 JVM 项目所需的底层基础设施。
6.1.1. 项目生成器
ProjectGenerator
类是项目生成的主要入口点。一个 ProjectGenerator
接收一个定义了要生成特定项目的 ProjectDescription
,以及一个负责基于可用候选项生成资产的 ProjectAssetGenerator
实现。
项目由 ProjectDescription
定义,它包含以下属性:
-
基本坐标,如
groupId
、artifactId
、name
、description
-
构建系统
BuildSystem
和打包方式Packaging
-
JVM 语言
Language
-
按 ID 索引的请求依赖项
-
项目使用的平台版本
Version
。这可用于根据选择的生成方式调整可用依赖项。 -
应用程序名称
application
-
根包名
-
项目的基础目录(如果与根目录不同)
项目生成发生在专用的应用程序上下文(ProjectGenerationContext
)中,这意味着对于生成的每个项目,上下文只包含与该特定项目相关的配置和组件。ProjectGenerationContext
的候选组件在带有 @ProjectGenerationConfiguration
注解的配置类中定义。如果这些配置类注册在 META-INF/spring.factories
中,它们将自动导入,如下例所示:
io.spring.initializr.generator.project.ProjectGenerationConfiguration=\ com.example.acme.build.BuildProjectGenerationConfiguration,\ com.example.acme.code.SourceCodeProjectGenerationConfiguration
添加到 ProjectGenerationContext
的组件通常使用条件使之可用。使用条件可以避免暴露必须检查是否需要执行某些操作的 bean,并使声明更符合习惯用法。考虑以下示例:
@Bean
@ConditionalOnBuildSystem(GradleBuildSystem.ID)
@ConditionalOnPackaging(WarPackaging.ID)
public BuildCustomizer<GradleBuild> warPluginContributor() {
return (build) -> build.plugins().add("war");
}
这会注册一个组件,该组件仅在要生成的项目使用 "Gradle" BuildSystem
和 "war" Packaging
时才能自定义 Gradle 构建。请查看 io.spring.initializr.generator.condition
包以了解更多条件。您可以轻松地通过继承 ProjectGenerationCondition
来创建自定义条件。
您只能在已加载到 ProjectGenerationConfiguration
中的 bean 上使用此类条件,因为它们需要具体的 ProjectDescription
bean 才能正常运行。
项目生成还可能依赖于不特定于特定项目配置的基础设施,并且通常在主 ApplicationContext
中配置,以避免在每次新请求到来时都注册它。一个常见的用例是将主 ApplicationContext
设置为 ProjectGenerationContext
的父级,如下例所示:
public ProjectGenerator createProjectGenerator(ApplicationContext appContext) {
return new ProjectGenerator((context) -> {
context.setParent(appContext);
context.registerBean(SampleContributor.class, SampleContributor::new);
});
}
这会创建一个新的 ProjectGenerator
,它可以使用应用程序的任何 bean,注册在 META-INF/spring.factories
中找到的所有贡献者,并以编程方式注册一个额外的 ProjectContributor
。
ProjectContributor
是一个可以实现的最高级别接口,用于向项目贡献资产。上面注册的 SampleContributor
会在项目结构的根目录生成一个 hello.txt
文件,如下所示:
public class SampleContributor implements ProjectContributor {
@Override
public void contribute(Path projectRoot) throws IOException {
Path file = Files.createFile(projectRoot.resolve("hello.txt"));
try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(file))) {
writer.println("Test");
}
}
}
6.1.2. 项目生成生命周期
当指示 ProjectGenerator
生成项目时,指定的 ProjectDescription
可以使用可用的 ProjectDescriptionCustomizer
bean 进行自定义,并且可以使用 Spring 的 Ordered
接口进行排序。对于希望了解原始 ProjectDescription
的某个属性是否被修改的扩展,提供了 ProjectDescriptionDiff
bean。
基于可用的 ProjectDescriptionCustomizer
s 对描述进行自定义后,生成器会使用 ProjectAssetGenerator
来生成项目资产。initializr-generator
模块提供了此接口的默认实现(DefaultProjectAssetGenerator
),它使用可用的 ProjectContributor
bean 生成目录结构。
虽然默认的 ProjectAssetGenerator
使用文件系统并调用特定的一组组件,但可以使用同一个 ProjectGenerator
实例配合完全专注于其他事情的自定义实现。
6.1.3. 项目抽象
此模块还包含项目各个方面的抽象以及一些便捷的实现:
-
具有 Maven 和 Gradle 实现的构建系统抽象。
-
具有 Java、Groovy 和 Kotlin 实现的语言抽象,包括每种实现的
SourceCodeWriter
。 -
具有
jar
和war
实现的打包抽象。
添加这些新的实现涉及创建 BuildSystemFactory
、LanguageFactory
和 PackagingFactory
,并将它们分别注册到 META-INF/spring.factories
中的 io.spring.initializr.generator.buildsystem.BuildSystemFactory
、io.spring.initializr.generator.language.LanguageFactory
和 io.spring.initializr.generator.packaging.PackagingFactory
下。
JVM 项目通常包含项目的构建配置。initializr-generator
模块提供了 Build
的模型,以及 Maven
和 Gradle
的实现。此模型可以根据约定进行操作。该库还提供了 MavenBuildWriter
和 GradleBuildWriter
,可以将 Build
模型转换为构建文件。
关于initializr-generator-spring
模块的下一节展示了如何使用 customizer 在构建文件写入之前操作 Build
。
6.2. Spring Boot 的约定
这是一个可选模块,定义了我们认为对任何 Spring Boot 项目都有用的约定。如果您的服务用于生成 Spring Boot 项目,则可以在您的项目中包含此 jar。
在项目生成器部分中,我们看到了如何使用 ProjectContributor
s 向项目贡献资产。此模块包含 ProjectContributor
的具体实现,以及配置它们的 @ProjectGenerationConfiguration
s。例如,存在一个 MavenBuildProjectContributor
,它贡献了 Maven 构建的文件,例如 pom.xml
。该贡献者在 ProjectGenerationConfiguration
中注册为一个 bean,该 bean 取决于构建系统是否为 Maven。
此模块还引入了 BuildCustomizer
s 的概念。BuildCustomizer
s 用于自定义项目的 Build
,并且是按顺序执行的。例如,如果您的服务要求向构建添加特定的插件,您可以提供一个添加该插件的 BuildCustomizer
,并且 customizer 将按照其上指定的顺序被调用。
6.2.1. 要求
此模块的贡献者期望在 ProjectGenerationContext
中提供以下 bean:
-
要使用的
InitializrMetadata
实例 -
(可选)一个
MetadataBuildItemResolver
,它可以根据元数据中的 ID 解析各种构建项(例如依赖项和 BOM)
如果您使用父上下文,建议在此处配置它们,因为您不应该在每次生成新项目时都注册它们。
-
一个表示要使用的缩进策略的
IndentingWriterFactory
。 -
一个使用
classpath:/templates
作为根位置的MustacheTemplateRenderer
。考虑使用缓存策略注册此类 bean,以避免每次都解析模板。
7. 创建您自己的实例
本节介绍如何创建自定义服务。
第一步是为您的实例创建一个新项目,并在构建中添加以下内容:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.spring.initializr</groupId>
<artifactId>initializr-web</artifactId>
</dependency>
<dependency>
<groupId>io.spring.initializr</groupId>
<artifactId>initializr-generator-spring</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.spring.initializr</groupId>
<artifactId>initializr-bom</artifactId>
<version>0.20.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
或者如果您使用 Gradle
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("io.spring.initializr:initializr-web")
implementation("io.spring.initializr:initializr-generator-spring")
dependencyManagement {
imports {
mavenBom "io.spring.initializr:initializr-bom:0.20.1"
}
}
假设自定义实例将使用 initializr-generator-spring 模块提供的约定来生成基于 Spring Boot 的项目。 |
启动应用程序后,您可以访问 localhost:8080。您将获得一个描述服务能力的 JSON 文档。任何选择的能力都不会有值。在本节的其余部分,我们将配置这些基本设置。
大多数设置通过 |
7.1. 配置基本设置
大多数选择的能力通过简单的基于列表的结构进行配置,其中每个条目都有一个 id
、一个 name
以及该条目是否为默认值。如果未提供 name
,则使用 id
。
让我们配置我们想要支持的语言和 JVM 版本:
initializr:
javaVersions:
- id: 11
default: false
- id: 1.8
default: true
languages:
- name: Java
id: java
default: true
- name: Kotlin
id: kotlin
default: false
如果您重新启动应用程序并刷新 localhost:8080,语言能力现在拥有上面定义的选项和默认值。
在此定义的语言标识符必须有相应的 Language 实现。java 、kotlin 和 groovy 可以开箱即用,因为它们在核心库本身中提供了实现。 |
可用的打包方式也可以这样配置:
initializr:
packagings:
- name: Jar
id: jar
default: true
- name: War
id: war
default: false
Jar 和 War 打包类型是开箱即用的。对于其他打包格式,您需要实现 Packaging 抽象并提供与其对应的 PackagingFactory 。 |
7.2. 配置仅文本设置
仅文本能力包括 groupId
、artifactId
、name
、description
、version
和 packageName
。如果未配置任何内容,每个能力都有一个默认值。默认值可以如下所示覆盖:
initializr:
group-id:
value: org.acme
artifact-id:
value: my-app
7.3. 配置可用的平台版本
您可以像配置其他能力一样配置可用的平台版本。
该概念参考了 bootVersions ,因为它早于平台版本概念出现。 |
initializr:
bootVersions:
- id: 2.4.0-SNAPSHOT
name: 2.4.0 (SNAPSHOT)
default: false
- id: 2.3.3.BUILD-SNAPSHOT
name: 2.3.3 (SNAPSHOT)
default: false
- id: 2.3.2.RELEASE
name: 2.3.2
default: true
上述配置提供了三个版本,默认使用 2.3.2
。然而,在实际中,您可能希望升级可用的平台版本,而无需每次都重新部署应用程序。实现您自己的 InitializrMetadataUpdateStrategy
bean 允许您在运行时更新元数据。
如果您查看Spring Boot 的项目主页,会显示最新版本。SpringIoInitializrMetadataUpdateStrategy
是该策略的一个实现,它获取最新的 Spring Boot 版本并更新元数据,以确保使用这些约定的正在运行的实例始终获得最新的可用版本。
如果您位于代理后面,或者需要自定义在幕后使用的 RestTemplate
,您可以在配置中定义一个 RestTemplateCustomizer
bean。有关更多详细信息,请查看文档。
如果您选择使用 SpringIoInitializrMetadataUpdateStrategy ,您必须配置缓存,以避免频繁请求该服务。 |
7.4. 配置可用的项目类型
可用的项目类型主要定义了生成项目的结构及其构建系统。一旦选择了项目类型,就会调用相关的操作来生成项目。
默认情况下,Spring Initializr 暴露以下资源(均通过 HTTP GET 访问):
-
/pom.xml
生成一个 Mavenpom.xml
-
/build.gradle
生成一个 Gradle 构建 -
/starter.zip
生成一个压缩为 zip 的完整项目结构 -
/starter.tgz
生成一个压缩为 tgz 的完整项目结构
必须使用 build
标签定义构建系统,该标签提供要使用的 BuildSystem
的名称(例如 maven
、gradle
)。
可以提供额外的标签来进一步限定条目。如果构建系统支持多种方言,可以使用 dialect
标签指定所选方言。
还有一个 format
标签可用于定义项目格式(例如,完整项目使用 project
,仅构建文件使用 build
)。默认情况下,HTML UI 过滤所有可用类型,仅显示带有值为 project
的 format
标签的类型。
您当然可以实现额外的端点来生成您需要的任何项目结构,但目前,我们仅将我们的实例配置为生成 Gradle 或 Maven 项目:
initializr:
types:
- name: Maven Project
id: maven-project
description: Generate a Maven based project archive
tags:
build: maven
format: project
default: true
action: /starter.zip
- name: Gradle Project
id: gradle-project
description: Generate a Gradle based project archive
tags:
build: gradle
format: project
default: false
action: /starter.zip
如果您打算针对您的服务构建自定义客户端,您可以添加任意数量的标签,并以对您的用户有意义的方式在客户端中处理它们。 |
例如,Spring Boot CLI 使用它们作为完整类型 ID 的快捷方式。因此,您无需按如下方式创建 Gradle 项目:
$ spring init --type=gradle-project my-project.zip
您只需定义一个更方便的构建参数:
$ spring init --build=gradle my-project.zip
完成这些配置后,您应该能够生成您的第一个项目了,恭喜!现在让我们添加依赖项,以便您可以开始搜索它们。
7.5. 配置依赖项
最基本的 dependency
由以下部分组成:
-
在客户端中用于引用它的
id
-
依赖项完整的 Maven 坐标(
groupId
和artifactId
) -
显示名称
name
(用于 UI 和搜索结果) -
可以(并且应该)添加
description
以提供关于依赖项的更多信息
Spring Initializr 自动将没有 Maven 坐标的依赖项视为定义了一个官方的 Spring Boot starter。在这种情况下,使用 id
来推断 artifactId
。
例如,以下配置了 spring-boot-starter-web
Starter:
initializr:
dependencies:
- name: Web
content:
- name: Web
id: web
description: Full-stack web development with Tomcat and Spring MVC
每个依赖项都包含在一个 分组 中,该分组收集共享共同表面区域或任何其他形式分组的依赖项。在上面的示例中,一个 Web
分组包含我们的唯一依赖项。分组还可以为各种设置提供默认值,请参阅专用操作指南以获取更多详细信息。
在我们的 spring-boot-starter-web
示例中,我们假设依赖项由平台进行 管理,因此无需为其提供 version
属性。您肯定需要定义平台未提供的其他依赖项,我们强烈建议您使用物料清单(BOM)。
如果没有可用的 BOM,您可以直接指定版本:
initializr:
dependencies:
- name: Tech
content:
- name: Acme
id: acme
groupId: com.example.acme
artifactId: acme
version: 1.2.0.RELEASE
description: A solid description for this dependency
如果您添加此配置并搜索 "acme"(或 "solid"),您会找到这个额外的条目;使用它生成一个 Maven 项目应该会向 POM 中添加以下内容:
<dependency>
<groupId>com.example.acme</groupId>
<artifactId>acme</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
本节的其余部分将详细介绍其他配置选项。
7.5.1. 兼容性范围
默认情况下,无论您选择了什么平台版本,依赖项都可用。如果您需要将某个依赖项限制到特定的平台版本,您可以向其定义中添加一个 compatibilityRange
属性,该属性定义了一个版本范围。版本范围是指与该依赖项组合时有效的平台版本范围。这些版本不应用于依赖项本身,而是在为生成的项目选择不同的平台版本时,用于过滤或修改该依赖项。
一个版本由四个部分组成:主修订版、次修订版、补丁修订版和一个可选的限定符。Spring Initializr 支持两种版本格式:
-
V1
是原始格式,限定符与版本之间用点分隔。它还使用明确定义的限定符来表示快照(BUILD-SNAPSHOT
)和正式版本(RELEASE
)。 -
V2
是一种改进的格式,符合 SemVer 规范,因此使用连字符分隔限定符。正式版本(GA)没有限定符。
说到限定符,它们的顺序如下:
-
M
表示里程碑版本(例如2.0.0.M1
是即将发布的 2.0.0 版本的第一个里程碑):可以看作是“测试版”发布 -
RC
表示发布候选版本(例如2.0.0-RC2
是即将发布的 2.0.0 版本的第二个发布候选版本) -
BUILD-SNAPSHOT
表示开发构建(2.1.0.BUILD-SNAPSHOT
代表即将发布的 2.1.0 版本的最新可用开发构建)。对于V2
格式,它就是简单的SNAPSHOT
,即2.1.0-SNAPSHOT
。 -
RELEASE
表示正式可用版本(GA)(例如2.0.0.RELEASE
就是 2.0.0 正式版)
快照在此方案中有点特殊,因为它们始终代表某个发布的“最新状态”。M1 代表给定主版本、次版本和补丁版本的最老版本,因此在指代该系列中的“第一个”发布时可以安全使用。 |
版本范围有下限和上限,如果边界是包含的,则用方括号([
或 ]
)表示,否则是排他的,用圆括号((
或 )
)表示。例如 [1.1.6.RELEASE,1.3.0.M1)
表示从 1.1.6.RELEASE
开始的所有版本,直到(但不包括) 1.3.0.M1
(具体来说,不包括 1.3.x
系列及之后的版本)。
版本范围可以是单个值,例如 1.2.0.RELEASE
,它是“此版本或更高版本”的缩写。这是一个包含的下限,并带有隐含的无限上限。
如果您需要在给定系列中指定“最新版本”,可以使用 x
代替硬编码的版本号。例如,1.4.x.BUILD-SNAPSHOT
是 1.4.x 系列的最新快照构建。例如,如果您想将一个依赖项限制在从 1.1.0.RELEASE
到 1.3.x 系列的最新稳定版本,您可以使用 [1.1.0.RELEASE,1.3.x.RELEASE]
。
快照自然是给定系列中最近期的版本,因此如果您希望将依赖项仅匹配到平台的最新快照版本,您可以使用版本范围 1.5.x.BUILD-SNAPSHOT
(假设 1.5 是最新的)。
请记住在 YAML 配置文件中引用版本范围的值(使用双引号 "")。 |
7.5.2. 仓库
如果依赖项在 Maven Central(或您端配置的任何默认仓库)上不可用,您还可以添加对仓库的引用。仓库在顶层(env
下)声明,并通过配置中的键为其指定 ID:
initializr:
env:
repositories:
my-api-repo-1:
name: repo1
url: https://example.com/repo1
定义后,可以在依赖项中引用该仓库:
initializr:
dependencies:
- name: Other
content:
- name: Foo
groupId: org.acme
artifactId: foo
version: 1.3.5
repository: my-api-repo-1
通常最好为每个依赖项设置一个 BOM,并将仓库附加到 BOM,而不是依赖项本身。
repo.spring.io 上的快照仓库和里程碑仓库分别使用 spring-snapshots 和 spring-milestones 标识符自动可用。 |
7.6. 配置物料清单 (BOM)
物料清单(BOM)是一种特殊的 pom.xml
文件,部署到 Maven 仓库,用于控制一组相关构件的依赖管理。在 Spring Boot 生态系统中,我们通常在 BOM 的 artifact ID 上使用后缀 -dependencies
。在其他项目中,我们看到的是 -bom
。建议将所有依赖项包含在某种 BOM 中,因为它们为依赖项的用户提供了很好的高级功能。同样重要的是,项目中使用的两个 BOM 不应包含同一依赖项的冲突版本,因此最佳实践是在添加新的 BOM 之前查看 Spring Initializr 中现有的 BOM,并确保您没有添加冲突。
在 Spring Initializr 中,BOM 在 env
级别声明,并通过配置键为其指定 ID。例如:
initializr:
env:
boms:
my-api-bom:
groupId: org.acme
artifactId: my-api-dependencies
version: 1.0.0.RELEASE
repositories: my-api-repo-1
如果 BOM 需要一个特殊的非默认仓库,则可以在此处引用它,而无需为每个依赖项再次明确列出仓库。依赖项或依赖项组可以通过引用 ID 来声明它需要使用一个或多个 BOM:
initializr:
dependencies:
- name: Other
content:
- name: My API
id : my-api
groupId: org.acme
artifactId: my-api
bom: my-api-bom
7.6.1. 根据平台版本映射坐标
除了依赖项或 BOM 的兼容性范围之外,您还可以使用版本映射以更细粒度的级别配置版本关系。依赖项或 BOM 有一个“映射”列表,每个映射都包含一个版本范围,以及一组一个或多个要为这些平台版本覆盖的依赖项属性。您可以使用映射来切换依赖项的版本,或者(更好)切换 BOM,或者更改其 artifact ID(例如,如果项目更改了其打包方式)。
下面是一个带有映射的 BOM 示例:
initializr:
env:
boms:
cloud-bom:
groupId: com.example.foo
artifactId: acme-foo-dependencies
mappings:
- compatibilityRange: "[1.2.3.RELEASE,1.3.0.RELEASE)"
groupId: com.example.bar
artifactId: acme-foo-bom
version: Arcturus.SR6
- compatibilityRange: "[1.3.0.RELEASE,1.4.0.RELEASE)"
version: Botein.SR7
- compatibilityRange: "[1.4.0.RELEASE,1.5.x.RELEASE)"
version: Castor.SR6
- compatibilityRange: "[1.5.0.RELEASE,1.5.x.BUILD-SNAPSHOT)"
version: Diadem.RC1
repositories: spring-milestones
- compatibilityRange: "1.5.x.BUILD-SNAPSHOT"
version: Diadem.BUILD-SNAPSHOT
repositories: spring-snapshots,spring-milestones
这里的主要用例是将平台版本映射到 Foo 项目的首选或支持版本。您还可以看到,对于里程碑和快照 BOM,声明了额外的仓库,因为这些构件不在默认仓库中。最初,该 BOM 的标识符是 com.example.bar:acme-foo-bom
,从 Botein
版本起重命名为 com.example.foo:acme-foo-dependencies
。
我们还在版本范围中使用了 x 这个技巧,以避免在每次有新的平台 1.5 错误修复版本可用时更新范围。 |
请参阅下面关于关联版本的部分,获取更多示例。
7.6.2. 别名
依赖项有一个 ID(例如 "web-services"),但可能需要提供一个新的 ID,同时仍能服务使用现已弃用的 ID 的客户端请求。为此,可以为该依赖项定义一个别名:
initializr:
dependencies:
- name: Other
content:
- name: Web Services
id: web-services
aliases:
- ws
现在可以使用 dependencies=ws
或 dependencies=web-services
生成同一个项目。
7.6.3. Facet
“Facet”是依赖项上的一个标签,用于驱动生成项目中的代码修改。例如,如果打包类型是 war
,initializr-generator-spring
会检查是否存在带有 web
facet 的依赖项。如果不存在带有 web
facet 的依赖项,它会引入 ID 为 web
的依赖项(如果此类依赖项不可用,则默认为 spring-boot-starter-web
)。
依赖项的 "facets" 属性的值是一个字符串列表。
7.6.4. 链接
链接可用于提供描述性数据和超链接数据,以指导用户了解有关依赖项的更多信息。依赖项具有一个 "links" 属性,它是一个 Link
列表。每个链接都有一个用于标识它的 rel
标签、一个 href
以及一个可选(但推荐)的 description
。
当前官方支持以下 rel
值
-
guide
:链接指向描述如何使用相关依赖项的指南。它可以是教程、操作方法或通常在 spring.io/guides 上提供的指南 -
reference
:链接通常指向开发者指南的某个部分或任何说明如何使用该依赖项的页面
如果 URL 的实际值可以根据环境变化,则可以使用模板。URL 参数用大括号指定,例如 example.com/doc/{bootVersion}/section
定义了一个 bootVersion
参数。
当前支持以下属性
-
bootVersion
:当前激活的平台版本(出于与元数据格式的向后兼容性,命名为bootVersion
)
这里有一个示例,为 acme
依赖项添加了两个链接
initializr:
dependencies:
- name: Tech
content:
- name: Acme
id: acme
groupId: com.example.acme
artifactId: acme
version: 1.2.0.RELEASE
description: A solid description for this dependency
links:
- rel: guide
href: https://com.example/guides/acme/
description: Getting started with Acme
- rel: reference
href: https://docs.example.com/acme/html
8. 使用 Web 端点生成项目
要发现特定实例的可用选项,只需“curl 它”。假设一个实例在您的机器上以默认端口运行,请调用以下命令
$ curl http://localhost:8080
或者,如果您更喜欢使用 HTTPie
,可以通过以下方式发现可用选项
$ http http://localhost:8080
结果是服务能力的文本表示,分为三个部分
首先,一张表描述了 可用的项目类型。
然后,一张表描述了 可用的参数。
最后,定义了依赖项列表。每个条目提供了在选择依赖项时必须使用的标识符、描述以及(如果适用)兼容范围。
除了服务能力之外,您还会找到一些示例,帮助您了解如何生成项目。这些示例显然是根据您使用的客户端定制的。
假设您想基于平台版本 2.3.5.RELEASE
,使用 web
和 devtools
依赖项(记住,这两个 ID 显示在服务能力中)生成一个名为 "my-project.zip" 的项目
$ curl -G http://localhost:8080/starter.zip -d dependencies=web,devtools \
-d bootVersion=2.3.5.RELEASE -o my-project.zip
如果您解压 my-project.zip
,您会注意到与 Web UI 生成的项目相比有一些差异
-
项目将解压到当前目录(Web UI 会自动添加一个与项目同名的基础目录)
-
项目名称不是
my-project
(-o
参数对项目名称没有影响)
也可以使用 http
命令生成完全相同的项目
$ http https://localhost:8080/starter.zip dependencies==web,devtools \
bootVersion==2.3.5.RELEASE -d
HTTPie 会读取与浏览器相同的提示,因此它会将一个 demo.zip 文件存储在当前目录中,并具有上面讨论的相同差异。 |
9. ‘操作方法’ 指南
本节提供了一些在使用 Spring Initializr 配置时经常出现的常见“我该如何做…”类型问题的答案。
9.1. 添加新的依赖项
要添加新的依赖项,首先确定要添加的依赖项的 Maven 坐标(groupId:artifactId:version
),然后检查它适用于哪些平台版本。如果存在适用于不同平台版本的多个版本,那也没问题。
-
如果有已发布的 BOM 管理您的依赖项版本,则首先在
env
部分添加该 BOM(参见 配置 BOM(物料清单))。 -
然后配置依赖项,如果可能,将其放入现有组中,否则创建一个新组。
-
如果有 BOM,则省略版本。
-
如果此依赖项需要兼容版本范围(或最小/最大版本),请将其添加为 关联版本。
9.2. 覆盖依赖项版本
有时,通常管理依赖项版本的 BOM 与最新版本发生冲突。或者这可能只发生在某个 Spring Boot 版本范围内。或者根本没有 BOM,或者不值得仅为一个依赖项创建一个 BOM。在这些情况下,您可以手动为依赖项指定版本,可以在顶层指定,也可以在 版本映射 中指定。在顶层指定时看起来像这样(只是依赖项中的一个 version
属性)
initializr:
dependencies:
- name: Tech
content:
- name: Acme
id: acme
groupId: com.example.acme
artifactId: acme
version: 1.2.0.RELEASE
description: A solid description for this dependency
9.3. 将平台版本关联到您的依赖项版本
如果您的依赖项需要特定的平台版本,或者不同的平台版本需要您的依赖项的不同版本,有几种机制可以配置这一点。
最简单的方法是在依赖项声明中设置一个 compatibilityRange
。这是一个平台版本的范围,而不是您的依赖项的版本范围。例如
initializr:
dependencies:
- name: Stuff
content:
- name: Foo
id: foo
...
compatibilityRange: 1.2.0.M1
- name: Bar
id: bar
...
compatibilityRange: "[1.5.0.RC1,2.0.0.M1)"
在此示例中,Foo
适用于平台版本 1.2.0
及更高版本,而 Bar
适用于从 1.5.0.RC1
开始直到但不包括 2.0.0.M1
的平台版本。
如果您的依赖项的不同版本适用于不同的平台版本,这时就需要 mappings
属性。映射是 compatibilityRange
和依赖项部分或全部其他属性的组合,它会覆盖顶层定义的值。例如
initializr:
dependencies:
- name: Stuff
content:
- name: Foo
id: foo
groupId: org.acme.foo
artifactId: foo-spring-boot-starter
compatibilityRange: 1.3.0.RELEASE
bom: cloud-task-bom
mappings:
- compatibilityRange: "[1.3.0.RELEASE,1.3.x.RELEASE]"
artifactId: foo-starter
- compatibilityRange: "1.4.0.RELEASE"
在此示例中,foo
的 artifact 从与平台版本 1.4.0
兼容的版本开始更改为 foo-spring-boot-starter
。此映射指示,如果选择平台版本 1.3.x
,artifactId 应设置为 foo-starter
。
映射也可以应用于 BOM 声明。例如
initializr:
env:
boms:
my-api-bom:
groupId: org.acme
artifactId: my-api-bom
additionalBoms: ['my-api-dependencies-bom']
mappings:
- compatibilityRange: "[1.0.0.RELEASE,1.1.6.RELEASE)"
version: 1.0.0.RELEASE
repositories: my-api-repo-1
- compatibilityRange: "1.2.1.RELEASE"
version: 2.0.0.RELEASE
repositories: my-api-repo-2
在此示例中,平台版本最高到 1.1.6
选择 BOM 的版本 1.0.0
,并设置不同的存储库。从 1.2.1
开始的平台版本选择 BOM 的版本 2.0.0
,并选择另一个存储库。
9.4. 配置 Snapshot 存储库
如果默认存储库(通常是 Maven Central)不包含某些 artifact,依赖项或 BOM 可能需要使用特定的存储库。通常,声明这一点最好的地方是在 BOM 配置中,但如果没有 BOM,您可以将其放在依赖项本身中。您还可以使用平台 版本映射 来覆盖依赖项或 BOM 的默认存储库。
9.5. 配置自定义 Parent POM
对于 Maven 项目,您可以按如下方式配置自定义 Parent POM
initializr:
env:
maven:
parent:
groupId: com.example
artifactId: my-parent
version: 1.0.0
relativePath: ../pom.xml
includeSpringBootBom : true
如果未指定 relativePath
,则从存储库解析 POM。
includeSpringBootBom
默认为 false
。当设置为 true
时,spring-boot-dependencies
BOM 将添加到 dependencyManagement
部分,其版本与项目使用的 Spring Boot 版本一致。
9.6. 确保常规依赖项引入基础 Starter
如果一个依赖项不能独立存在(特别是它不依赖于现有的 Spring Boot Starter),您可以将其标记为“非 Starter”
initializr:
dependencies:
- name: Stuff
content:
- name: Lib
id: lib
groupId: com.acme
artifactId: lib
starter: false
当生成的项目仅包含设置了此标志的依赖项时,基础 Spring Boot Starter 也会被添加。
9.7. 在组中共享常见的依赖项设置
依赖项组是用户界面实现的提示,用于在用户选择依赖项时将相关项分组。它也是在依赖项之间共享设置的便捷方式,因为每个依赖项都会继承所有设置。组中最常见的设置是 groupId
、compatibilityRange
和 bom
initializr:
dependencies:
- name: Stuff
bom: stuff-bom
compatibilityRange: "[1.3.0.RELEASE,2.0.0.M1)"
content:
...
默认情况下,这些依赖项仅适用于平台版本 1.3.0.RELEASE
及更高版本,直到但不包括 2.0.0.M1
,并且会引入 stuff-bom
BOM。
9.8. 配置 Kotlin 版本映射
默认情况下,要使用的 Kotlin 版本从元数据中推断。以下示例展示了如何根据平台版本映射两个 Kotlin 版本。
initializr:
env:
kotlin:
mappings:
- compatibilityRange: "[2.0.0.RELEASE,2.4.0-M1)"
version: 1.2
- compatibilityRange: "2.4.0-M1"
version: 1.3
对于更高级的解析,请考虑实现一个 KotlinVersionResolver
bean。
9.9. 配置平台版本格式
Spring Initializr 支持两种格式:V1
是元数据版本最高到 2.1
定义的原始格式。从元数据版本 2.2
开始,提供了与 V1
并存的 SemVer 格式 V2
。为了提供向后兼容的内容,应配置每种格式的版本范围,以便进行相应的转换。
假设一个实例仅支持 2.0.0
及更高版本,并且平台版本最高到 2.4.0
(不包括)使用原始格式。从 2.4.0
开始,使用改进的 SemVer 格式。以下配置使实例自动适应版本格式
initializr:
env:
platform:
compatibility-range: "2.0.0.RELEASE"
v1-format-compatibility-range: "[2.0.0.RELEASE,2.4.0-M1)"
v2-format-compatibility-range: "2.4.0-M1"
10. 高级配置
10.1. 缓存配置
如果您使用该服务,您会注意到日志中有许多带有消息 Fetching boot metadata from api.spring.io/projects/spring-boot/releases
的条目。为避免过于频繁地检查最新的 Spring Boot 版本,您应在服务上启用缓存。
如果您愿意使用 JCache
(JSR-107
) 实现,Spring Initializr 提供了请求缓存的自动配置。默认情况下,服务元数据缓存配置了过期策略,允许条目在缓存中保留 10 分钟。
缓存是使用自动配置的 JCacheManagerCustomizer 创建的,顺序为 0 ,并且只有在它们不存在时才会创建。您可以贡献一个相同类型的 bean,使用较低的 @Order 来覆盖部分配置以满足您的特定需求。 |
添加 javax.cache:cache-api
和您喜欢的 JCache 实现,并通过将 @EnableCaching
添加到您的 @SpringBootApplication
来简单地启用缓存。例如,您可以通过添加以下内容来使用 ehcache
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
或者如果您使用 Gradle
implementation("javax.cache:cache-api")
implementation("org.ehcache:ehcache")
您会注意到日志条目变得更加罕见。如果您不想使用 JSR-107,应自行配置缓存。以下是应用程序使用的缓存(每个缓存都需要一些配置才能正常工作)
缓存名称 | 描述 |
---|---|
|
缓存服务的完整元数据。当元数据过期时,它会再次被完全解析(可能包括网络调用以确定最新的平台版本)。请相应地调整过期设置。 |
|
缓存特定于依赖项的元数据。 |
|
缓存用于生成项目的模板。 |
10.2. 绑定到自定义项目请求
只有元数据中定义的属性才能绑定到 ProjectRequest
并最终在 ProjectDescription
中可用。但是,自定义实例可以选择提供额外的属性。请注意,官方客户端(即 IDE)不会支持这些属性。
第一步是定义一个包含您的额外属性的自定义 ProjectRequest
,并创建一个绑定到它的自定义 ProjectGenerationController
public class CustomProjectGenerationController extends ProjectGenerationController<CustomProjectRequest> {
public CustomProjectGenerationController(InitializrMetadataProvider metadataProvider,
ProjectGenerationInvoker<CustomProjectRequest> projectGenerationInvoker) {
super(metadataProvider, projectGenerationInvoker);
}
@Override
public CustomProjectRequest projectRequest(Map<String, String> headers) {
CustomProjectRequest request = new CustomProjectRequest();
request.getParameters().putAll(headers);
request.initialize(getMetadata());
return request;
}
}
如果您继承自 WebProjectRequest
,可以如上所示自动应用元数据中的默认值,但您也可以选择忽略这一点。
下一步是确保这些额外属性在 ProjectGenerationContext
中可用。典型的做法是创建自己的接口,该接口继承自 ProjectDescription
并暴露您的自定义属性。为了确保您的 ProjectDescription
视图在 ProjectGenerationContext
中可用,应定义一个自定义的 ProjectRequestToDescriptionConverter
,并且可以重用 DefaultProjectRequestToDescriptionConverter
来应用标准字段的通用规则。
最后,您应该将所有内容连接起来
@Bean
public CustomProjectGenerationController projectGenerationController(InitializrMetadataProvider metadataProvider,
ApplicationContext applicationContext) {
ProjectGenerationInvoker<CustomProjectRequest> projectGenerationInvoker = new ProjectGenerationInvoker<>(
applicationContext, new CustomProjectRequestToDescriptionConverter());
return new CustomProjectGenerationController(metadataProvider, projectGenerationInvoker);
}
API 指南
11. 元数据格式
本节描述了 Initializr 暴露的元数据的 hal/json
结构。第三方客户端可以使用此类元数据提供可用于请求创建项目的选项列表和默认设置。
建议第三方客户端为发送到服务的每个请求设置 User-Agent
请求头。用户代理的良好结构是 clientId/clientVersion
(例如,"foo" 客户端版本 1.2.0
为 foo/1.2.0
)。
11.1. 服务能力
任何第三方客户端都可以通过对根 URL 发出 GET
请求并使用以下 Accept
请求头来检索服务能力:application/vnd.initializr.v2.2+json
。请注意,未来元数据可能会以非向后兼容的方式演变,因此添加此请求头可确保服务返回您期望的元数据格式。
支持以下版本
-
v2
初始版本,仅支持 V1 版本格式 -
v2.1
支持兼容范围和依赖项链接 -
v2.2
(当前)支持 V1 和 V2 版本格式。
这是在 start.example.com
运行的服务的输出示例
GET / HTTP/1.1
Accept: application/vnd.initializr.v2.2+json
Host: start.example.com
HTTP/1.1 200 OK
ETag: "02842ebd1bdc7f2250fd7e76c2840951"
Content-Type: application/vnd.initializr.v2.2+json
Vary: Accept
Cache-Control: max-age=7200
Content-Length: 4842
{
"_links" : {
"maven-build" : {
"href" : "http://start.example.com/pom.xml?type=maven-build{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
"templated" : true
},
"maven-project" : {
"href" : "http://start.example.com/starter.zip?type=maven-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
"templated" : true
},
"gradle-build" : {
"href" : "http://start.example.com/build.gradle?type=gradle-build{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
"templated" : true
},
"gradle-project" : {
"href" : "http://start.example.com/starter.zip?type=gradle-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
"templated" : true
},
"dependencies" : {
"href" : "http://start.example.com/dependencies{?bootVersion}",
"templated" : true
}
},
"dependencies" : {
"type" : "hierarchical-multi-select",
"values" : [ {
"name" : "Core",
"values" : [ {
"id" : "web",
"name" : "Web",
"description" : "Web dependency description",
"_links" : {
"guide" : {
"href" : "https://example.com/guide",
"title" : "Building a RESTful Web Service"
},
"reference" : {
"href" : "https://example.com/doc"
}
}
}, {
"id" : "security",
"name" : "Security"
}, {
"id" : "data-jpa",
"name" : "Data JPA"
} ]
}, {
"name" : "Other",
"values" : [ {
"id" : "org.acme:foo",
"name" : "Foo",
"_links" : {
"guide" : [ {
"href" : "https://example.com/guide1"
}, {
"href" : "https://example.com/guide2",
"title" : "Some guide for foo"
} ],
"reference" : {
"href" : "https://example.com/{bootVersion}/doc",
"templated" : true
}
}
}, {
"id" : "org.acme:bar",
"name" : "Bar"
}, {
"id" : "org.acme:biz",
"name" : "Biz",
"versionRange" : "2.6.0-SNAPSHOT"
}, {
"id" : "org.acme:bur",
"name" : "Bur",
"versionRange" : "[2.4.4,2.5.0-SNAPSHOT)"
}, {
"id" : "my-api",
"name" : "My API"
} ]
} ]
},
"type" : {
"type" : "action",
"default" : "maven-project",
"values" : [ {
"id" : "maven-build",
"name" : "Maven POM",
"action" : "/pom.xml",
"tags" : {
"build" : "maven",
"format" : "build"
}
}, {
"id" : "maven-project",
"name" : "Maven Project",
"action" : "/starter.zip",
"tags" : {
"build" : "maven",
"format" : "project"
}
}, {
"id" : "gradle-build",
"name" : "Gradle Config",
"action" : "/build.gradle",
"tags" : {
"build" : "gradle",
"format" : "build"
}
}, {
"id" : "gradle-project",
"name" : "Gradle Project",
"action" : "/starter.zip",
"tags" : {
"build" : "gradle",
"format" : "project"
}
} ]
},
"packaging" : {
"type" : "single-select",
"default" : "jar",
"values" : [ {
"id" : "jar",
"name" : "Jar"
}, {
"id" : "war",
"name" : "War"
} ]
},
"javaVersion" : {
"type" : "single-select",
"default" : "1.8",
"values" : [ {
"id" : "1.6",
"name" : "1.6"
}, {
"id" : "1.7",
"name" : "1.7"
}, {
"id" : "1.8",
"name" : "1.8"
} ]
},
"language" : {
"type" : "single-select",
"default" : "java",
"values" : [ {
"id" : "groovy",
"name" : "Groovy"
}, {
"id" : "java",
"name" : "Java"
}, {
"id" : "kotlin",
"name" : "Kotlin"
} ]
},
"bootVersion" : {
"type" : "single-select",
"default" : "2.4.4",
"values" : [ {
"id" : "2.5.0-SNAPSHOT",
"name" : "Latest SNAPSHOT"
}, {
"id" : "2.4.4",
"name" : "2.4.4"
}, {
"id" : "2.3.10.RELEASE",
"name" : "2.3.10"
} ]
},
"groupId" : {
"type" : "text",
"default" : "com.example"
},
"artifactId" : {
"type" : "text",
"default" : "demo"
},
"version" : {
"type" : "text",
"default" : "0.0.1-SNAPSHOT"
},
"name" : {
"type" : "text",
"default" : "demo"
},
"description" : {
"type" : "text",
"default" : "Demo project for Spring Boot"
},
"packageName" : {
"type" : "text",
"default" : "com.example.demo"
}
}
当前能力如下
-
项目依赖项:这些实际上是 Starters,或者任何我们可能想要添加到项目的依赖项。
-
项目类型:这些定义了可以在此服务上调用的操作以及操作将生成什么(例如,包含预配置 Maven 项目的 zip 文件)的描述。每种类型可能有一个或多个标签,进一步定义它生成的内容。
-
打包方式:要生成的项目类型。这仅向负责生成项目的组件提供提示(例如,生成一个可执行的 jar 项目)。
-
Java 版本:支持的 Java 版本
-
语言:要使用的语言(例如 Java)
-
Boot 版本:要使用的平台版本
-
额外的基本信息,例如:
groupId
、artifactId
、version
、name
、description
和packageName
。
每个顶层属性(即能力)都具有标准格式
-
定义属性语义的
type
属性(见下文)。 -
定义默认值或默认值引用的
default
属性。 -
定义可接受值集合(如果存在)的
values
属性。它可以是分层的(values
中包含values
)。values
数组中的每个项可以有一个id
、name
和description
)。
支持以下属性 type
-
text
:定义一个没有选项的简单文本值。 -
single-select
:定义一个从指定选项中选择的简单值。 -
hierarchical-multi-select
:定义一组分层值(values 中包含 values),能够选择多个值。 -
action
:一个特殊类型,定义了要使用的操作属性。
每个操作都定义为符合 HAL 规范的 URL。例如,maven-project
类型的模板化 URL 定义如下
{
"href" : "http://start.example.com/starter.zip?type=maven-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
"templated" : true
}
您可以使用 Spring HATEOAS,特别是 UriTemplate
助手,从模板变量生成 URI。请注意,变量与元数据文档中的顶层属性名称匹配。如果您无法解析此类 URI,则每种类型的 action
属性提供了要在服务器上调用的根操作。这需要您进行更多的手动处理。
11.1.1. 项目依赖项
依赖项通常是 Starter 模块的坐标,但它也可以只是一个常规依赖项。典型的依赖项结构如下所示
{
"name": "Display name",
"id": "org.acme.project:project-starter-foo",
"description": "What starter foo does"
}
名称用作远程客户端使用的任何 UI 中显示的显示名称。id 可以是任何东西,因为实际的依赖项定义是通过配置定义的。如果没有定义 id,则使用依赖项的 groupId
和 artifactId
构建一个默认 id。特别要注意的是,版本绝不用作自动 id 的一部分。
每个依赖项都属于一个组。组的目的是将类似的依赖项聚集在一起并对其进行排序。这里是一个包含 core
组的值,用于说明此功能
{
"name" : "Core",
"values" : [ {
"id" : "web",
"name" : "Web",
"description" : "Web dependency description",
"_links" : {
"guide" : {
"href" : "https://example.com/guide",
"title" : "Building a RESTful Web Service"
},
"reference" : {
"href" : "https://example.com/doc"
}
}
}, {
"id" : "security",
"name" : "Security"
}, {
"id" : "data-jpa",
"name" : "Data JPA"
} ]
}
每个依赖项都可以有 链接(以符合 HAL 规范的格式)。链接按“关系”分组,这些“关系”提供了链接的语义。链接还可以有一个 标题,其 URI 可以模板化。目前,唯一有效的参数是 bootVersion
。
官方关系如下
-
guide
:链接到说明如何入门的操作方法或指南 -
reference
:链接到参考指南(文档)的某个部分
11.1.2. 项目类型
type
元素定义了可以生成什么样的项目以及如何生成。例如,如果服务暴露了生成 Maven 项目的能力,它将看起来像这样
{
"id" : "maven-build",
"name" : "Maven POM",
"action" : "/pom.xml",
"tags" : {
"build" : "maven",
"format" : "build"
}
}
您不应依赖于该信息来判断输出格式。始终使用响应头中定义的 Content-Type
和 Content-Disposition
请求头。
请注意,每个 id 都有一个相关的符合 HAL 规范的链接,可用于基于模板变量生成正确的 URI。顶层 type
与任何其他属性一样,有一个 default
属性,这是一个提示,用于选择服务认为的最佳默认值。
如果您无法使用符合 HAL 规范的 URL,action
属性定义了客户端应该联系以实际生成该类型项目的端点。
tags
对象用于对项目类型进行分类并向第三方客户端提供 提示。例如,build 标签定义了项目将使用的构建系统,format 标签定义了生成内容的格式(即,这里是完整项目与构建文件之间的区别。注意,响应的 Content-type
请求头提供了额外的元数据)。
12. 使用 Stubs
Spring Initializr 项目为项目中测试的所有 JSON 响应发布 WireMock stubs。如果您正在为 Spring Initializr 服务编写客户端,可以使用这些 stubs 测试自己的代码。您可以使用原始 Wiremock API 或通过 Spring Cloud Contract 的一些功能来消费它们。
WireMock 是一个嵌入式 Web 服务器,它分析传入的请求并根据匹配某些规则(例如特定请求头值)选择 stub 响应。因此,如果您向它发送一个与某个 stub 匹配的请求,它将发送给您一个响应,就像它是一个真实的 Initializr 服务一样,您可以使用它对您的客户端进行全栈集成测试。 |
12.1. 在 Spring Boot 中使用 WireMock
12.1.1. 从 Classpath 加载 Stubs
在您的项目中消费 stubs 的便捷方法是添加一个测试依赖项
<dependency>
<groupId>io.spring.initializr</groupId>
<artifactId>initializr-web</artifactId>
<classifier>stubs</classifier>
<version>0.20.1</version>
<scope>test</scope>
</dependency>
然后从 classpath 中提取 stubs。在 Spring Boot 应用程序中,使用 Spring Cloud Contract,您可以启动一个 WireMock 服务器并将所有 stubs 注册到其中,如下面的基于 JUnit 5 的示例所示
@SpringBootTest
@AutoConfigureWireMock(port = 0,
stubs="classpath:META-INF/io.spring.initializr/initializr-web/0.20.1")
class ClientApplicationTests {
@Value("${wiremock.server.port}")
private int port;
...
}
Wiremock 功能随 Spring Cloud Contract Wiremock 一起提供
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-wiremock</artifactId>
<scope>test</scope>
</dependency>
此依赖项由 spring-cloud-contract-dependencies BOM 管理。 |
12.1.2. 使用 Stub Runner
或者,您可以使用另一个 Spring Cloud Contract 依赖项:spring-cloud-starter-contract-stub-runner
来配置 Stub Runner 以查找 artifact。下面的示例将在必要时自动下载 Spring Initializr stubs 的指定版本(这样您就不需要将 stubs 声明为依赖项)。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-stubrunner</artifactId>
<scope>test</scope>
</dependency>
测试应改用 @AutoConfigureStubRunner
,如下面的基于 JUnit 5 的示例所示
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
@AutoConfigureStubRunner(
ids = "io.spring.initializr:initializr-web:0.20.1",
repositoryRoot = "https://repo.spring.io/1")
class ClientApplicationTests {
@Autowired
private StubFinder stubFinder;
...
}
以下是一个基于 JUnit 5 的测试示例,用于检索服务的元数据。这里的断言并不重要,但它说明了如何将其集成到自定义客户端的测试套件中
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = "io.spring.initializr:initializr-web:${project.version}", stubsMode = StubsMode.LOCAL)
class ClientApplicationTests {
@Autowired
private StubFinder stubFinder;
@Autowired
private RestTemplate restTemplate;
@Test
void testCurrentMetadata() {
RequestEntity<Void> request = RequestEntity.get(createUri("/"))
.accept(MediaType.valueOf("application/vnd.initializr.v2.1+json"))
.build();
ResponseEntity<String> response = this.restTemplate.exchange(request, String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
// other assertions here
}
private URI createUri(String path) {
String url = this.stubFinder.findStubUrl("initializr-web").toString();
return URI.create(url + path);
}
@TestConfiguration
static class Config {
@Bean
RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
}
然后您就有一个服务器,当您向其发送请求头 Accept:application/vnd.initializr.v2.2+json
(推荐方式)时,它会返回 JSON 元数据的 stub(metadataWithCurrentAcceptHeader.json
)。
12.2. Stubs 的名称和路径
Stubs 以某种形式(在 "**/mappings" 下)分布在 jar 文件中,WireMock 只需设置其文件源即可消费这些 stubs。各个 stubs 的名称与在 Spring Initializr 项目中生成它们的测试用例的方法名称相同。例如,在 MainControllerIntegrationTests
中有一个名为 "metadataWithV2AcceptHeader" 的测试用例,它断言当 accept 请求头为 application/vnd.initializr.v2.1+json
时的响应。响应记录在 stub 中,如果在客户端使用了与 Spring Initializr 测试用例中相同的请求头和请求参数,则它将在 WireMock 中匹配。方法名称通常概括了这些值是什么。
Stub Runner 以及上面示例中的 @AutoConfigureWireMock
会将所有 stubs 加载到 WireMock 中,因此您不一定需要知道 stubs 的名称。但是,您也可以逐个注册 stubs,在这种情况下,扫描 stubs jar 并将文件名与测试方法进行比较将有所帮助。例如,如果您查看 stubs jar,您会看到一个名为 metadataWithV2AcceptHeader.json
的文件,并且在 initializr-web 项目中,有一个名为 metadataWithV2AcceptHeader
的测试方法生成了它。