Spring Initializr 文档

本节简要概述了 Spring Initializr 参考文档:将其视为文档其余部分的地图。某些部分针对特定受众,因此本参考指南并非旨在以线性方式阅读。

Spring Initializr 提供了一个可扩展的 API 来生成基于 JVM 的项目,并检查用于生成项目的元数据,例如列出可用的依赖项和版本。

文档大致分为三个部分

  • 简介:本节介绍了该库以及如何与服务交互以生成项目。

  • 配置指南:本节介绍了如何在您自己的应用程序中使用 jar 作为库来创建您自己的 Spring Initializr 实例。

  • API 指南:本节介绍了用于项目生成的 API。API 可以独立使用或嵌入到其他工具中(例如,它用于 Spring Tool Suite、IntelliJ IDEA Ultimate、Netbeans 和 VSCode 等主要 IDE)。

您可以轻松地使用 Spring Initializr 创建您自己的实例,方法是在您自己的应用程序中使用 jar 作为库。涉及的代码最少,并且服务具有非常丰富的配置结构,允许您不仅定义各种项目属性的值,还定义依赖项列表以及要应用于它们的约束。如果这听起来很有趣,那么配置指南提供了您需要的所有详细信息。您可能只想修改现有的 Spring Initializr 实例,例如添加新的依赖项类型或更新现有依赖项的版本。对于这些和其他简单且常见的用例,请查看“操作指南”

Spring Initializr 还提供了一个可扩展的 API 来生成基于 JVM 的项目,并检查用于生成项目的元数据,例如列出可用的依赖项和版本。API 可以独立使用或嵌入到其他工具中(例如,它用于 Spring Tool Suite、IntelliJ IDEA Ultimate、Netbeans 和 VSCode 等主要 IDE)。这些功能在API 指南中介绍。

1. 关于文档

Spring Initializr 参考指南以html格式提供。最新版本可在docs.spring.io/initializr/docs/current/reference/html找到。

您可以出于自身使用和分发给他人的目的复制本文件,前提是您不收取任何此类副本的费用,并且进一步规定每个副本都包含本版权声明,无论是在印刷版还是电子版中分发。

2. 获取帮助

在使用 Spring Initializr 时遇到问题?我们很乐意提供帮助!

所有 Spring Initializr 都是开源的,包括文档!如果您发现文档存在问题;或者您只是想改进它们,请参与进来

简介

这是对 Spring Initializr 功能的简要介绍。您将了解与 Spring Initializr 服务交互的各种方法,并深入了解其功能。

该服务允许您快速生成基于 JVM 的项目。您可以自定义要生成的项目:构建系统和打包、语言、打包、坐标、平台版本以及最后要添加到项目的依赖项。

3. 项目元数据

Spring Initializr 公开了许多可用于生成基于 JVM 的项目的端点。您可以轻松地创建您自己的实例,方法是提供各种核心概念的元数据。

基于元数据和贡献者列表,提供了一个项目生成引擎来生成实际项目的资产。生成的输出可以是包含项目的目录或任何其他内容。

4. Web 端点

此库可用于 Web 应用程序中,以公开用于处理项目生成的一些端点。服务的入口点是其元数据端点,可在上下文的根目录中找到。它由各种客户端使用来确定可用的选项,并在可能的情况下将其呈现给用户。

元数据端点还列出了可以生成的项目类型以及服务如何触发它们。

5. 支持的客户端

开箱即用,自定义实例使用cURLHTTPie处理命令行请求。Spring Initializr 也在各种 IDE 中得到支持,请查看您喜欢的 IDE 的文档以了解更多详细信息。

Spring Initializr 不提供与服务交互的 Web UI。

配置指南

您可以使用 Spring Initializr 创建您自己的服务,该服务可以生成 JVM 项目。本节介绍如何创建您自己的服务并根据您的需求对其进行调整,以及如何配置现有服务。

6. 项目生成概述

在开始创建您自己的服务之前,让我们先了解项目生成的核心概念以及库如何构建以支持它们。

Initializr 分散在多个模块中

  • initializr-actuator:可选模块,用于提供有关项目生成的附加信息和统计信息。

  • initializr-bom:为您的项目提供物料清单,以便更轻松地管理依赖项。

  • 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-generatorinitializr-generator-spring

6.1. Initializr 生成器

initializr-generator模块包含生成基于 JVM 的项目所需的低级基础结构。

6.1.1. 项目生成器

ProjectGenerator类是项目生成的主要入口点。ProjectGenerator接受一个ProjectDescription,该描述定义了要生成的特定项目,以及一个ProjectAssetGenerator的实现,该实现负责根据可用的候选项生成资产。

项目由ProjectDescription定义,它包含以下属性

  • 基本坐标,例如groupIdartifactIdnamedescription

  • BuildSystemPackaging

  • 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 被指示生成一个项目时,可以使用可用的 ProjectDescriptionCustomizer bean 自定义指定的 ProjectDescription,并且可以使用 Spring 的 Ordered 接口对其进行排序。对于希望知道原始 ProjectDescription 的某个属性是否被修改的扩展,可以使用 ProjectDescriptionDiff bean。

一旦根据可用的 ProjectDescriptionCustomizer 自定义了描述,生成器就会使用 ProjectAssetGenerator 生成项目资源。initializr-generator 模块为此接口提供了一个默认实现(`DefaultProjectAssetGenerator),该实现使用可用的 ProjectContributor bean 生成目录结构。

虽然默认的 ProjectAssetGenerator 使用文件系统并调用一组特定的组件,但可以使用相同的 ProjectGenerator 实例与完全专注于其他内容的自定义实现。

6.1.3. 项目抽象

此模块还包含项目各个方面的抽象以及一些方便的实现

  • 具有 Maven 和 Gradle 实现的构建系统抽象。

  • 具有 Java、Groovy 和 Kotlin 实现的语言抽象,包括每个实现的 SourceCodeWriter

  • 具有 jarwar 实现的打包抽象。

添加这些新实现涉及创建 BuildSystemFactoryLanguageFactoryPackagingFactory,并在 META-INF/spring.factories 中分别在 io.spring.initializr.generator.buildsystem.BuildSystemFactoryio.spring.initializr.generator.language.LanguageFactoryio.spring.initializr.generator.packaging.PackagingFactory 下注册它们。

JVM 项目通常包含项目的构建配置。initializr-generator 模块为 Build 提供了一个模型,其中包含 MavenGradle 的实现。可以根据约定操作此模型。库还提供了一个 MavenBuildWriterGradleBuildWriter,它们可以将 Build 模型转换为构建文件。

下一节关于 initializr-generator-spring 模块展示了如何在使用自定义器编写构建文件之前操作 Build

6.2. Spring Boot 约定

这是一个可选模块,它定义了我们认为对任何 Spring Boot 项目都很有用的约定。如果您的服务旨在生成 Spring Boot 项目,则可以在您的项目中包含此 jar。

项目生成器部分 中,我们了解了如何使用 ProjectContributor 向项目贡献资源。此模块包含 ProjectContributor 的具体实现以及配置它们的 @ProjectGenerationConfiguration。例如,有一个 MavenBuildProjectContributor,它贡献了 Maven 构建的文件,例如 pom.xml。此贡献者在 ProjectGenerationConfiguration 中注册为 bean,该 bean 以构建系统为 Maven 为条件。

此模块还引入了 BuildCustomizer 的概念。BuildCustomizer 用于自定义项目的 Build 并且是有序的。例如,如果您的服务要求您向构建中添加某个插件,则可以提供一个添加该插件的 BuildCustomizer,并且该自定义器将根据其上指定的顺序被调用。

6.2.1. 需求

此模块的贡献者期望以下 bean 在 ProjectGenerationContext 中可用

  • 要使用的 InitializrMetadata 实例

  • 可选地,一个 MetadataBuildItemResolver,它可以解析各种构建项(例如,基于元数据中其 ID 的依赖项和 BOM)

如果您正在使用父上下文,建议在那里配置它们,因为您不应该在每次生成新项目时都注册它们

  • 一个表示要使用的缩进策略的 IndentingWriterFactory

  • 一个使用 classpath:/templates 作为根位置的 MustacheTemplateRenderer。考虑使用缓存策略注册此类 bean 以避免每次都解析模板。

6.2.2. 支持的方面

处理以下方面

  • web:用于驱动包含 ID 为 web 的依赖项(如果不存在具有该方面的依赖项,则默认为 spring-boot-starter-web

  • jpa:用于标记此项目使用 JPA。当与 Kotlin 结合使用时,这将确保配置适当的插件

  • json:用于标记此项目依赖于 Jackson。当与 Kotlin 结合使用时,这将确保添加 Kotlin 特定的 jackson 模块以获得更好的互操作性。

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 文档。没有一个选择功能将具有值。在本节的其余部分,我们将配置这些基本设置。

大多数设置都是通过使用 initializr 命名空间的 application.properties 配置的。由于配置是高度分层的,我们建议使用 yaml 格式,因为它更易于阅读此类结构。如果您同意,请在 src/main/resources 中创建一个 application.yml

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 实现。javakotlingroovy 可以开箱即用,因为核心库本身提供了它们的实现。

可用的打包方式也可以这样配置

initializr:
  packagings:
    - name: Jar
      id: jar
      default: true
    - name: War
      id: war
      default: false
JarWar 打包类型可开箱即用。对于其他打包格式,您需要实现 Packaging 抽象并提供与之对应的 PackagingFactory

7.2. 配置纯文本设置

纯文本功能包括 groupIdartifactIdnamedescriptionversionpackageName。如果未配置任何内容,则每个功能都有一个默认值。可以如下所示覆盖默认值

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 生成 Maven pom.xml

  • /build.gradle 生成 Gradle 构建

  • /starter.zip 生成一个完整的项目结构,打包在 zip 中

  • /starter.tgz 生成一个完整的项目结构,打包在 tgz 中

构建系统必须使用提供要使用的 BuildSystem 名称(例如 mavengradle)的 build 标签进行定义。

可以提供其他标签来进一步限定条目。如果构建系统支持多种方言,则可以使用 dialect 标签指定所选方言。

还有一个 format 标签可用于定义项目的格式(例如,完整项目的 project,仅构建文件的 build)。默认情况下,HTML UI 会过滤所有可用类型,只显示格式标签值为 project 的类型。

当然,您可以实现其他端点来生成所需的任何项目结构,但现在,我们将简单地配置我们的实例以生成 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 坐标(groupIdartifactId

  • 显示 name(在 UI 和搜索结果中使用)

  • 可以(也应该)添加 description 以提供有关依赖项的更多信息

Spring Initializr 自动认为没有 maven 坐标的依赖项定义了官方的 Spring Boot 启动器。在这种情况下,id 用于推断 artifactId

例如,以下内容配置了 spring-boot-starter-web 启动器

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 表示通用可用性(例如,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-snapshotsspring-milestones标识符自动可用。

7.6. 配置物料清单

物料清单 (BOM) 是一种特殊的pom.xml,部署到 Maven 仓库,用于控制一组相关工件的依赖项管理。在 Spring Boot 生态系统中,我们通常在 BOM 的工件 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,或更改其工件 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=wsdependencies=web-services生成相同的项目。

7.6.3. 面

“面”是依赖项上的一个标签,用于在生成的项目中驱动代码修改。例如,如果打包类型为war,则initializr-generator-spring会检查是否存在具有web面的依赖项。缺少具有web面的依赖项会驱动包含 ID 为web的依赖项(如果此类依赖项不可用,则默认为spring-boot-starter-web)。

依赖项的“面”属性的值是一个字符串列表。

链接可用于提供描述性和超链接数据,以指导用户了解有关依赖项的更多信息。依赖项具有一个“链接”属性,它是一个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 https://127.0.0.1:8080

或者,如果您更喜欢HTTPie,您可以按如下方式发现可用选项

$ http https://127.0.0.1:8080

结果是服务功能的文本表示,分为三个部分

首先,一个描述可用项目类型的表格。

然后,一个描述可用参数的表格。

最后,定义依赖项列表。每个条目都提供了您要选择依赖项时必须使用的标识符、描述和兼容性范围(如果有)。

除了服务的功能外,您还会找到一些示例,帮助您了解如何生成项目。这些显然是针对您正在使用的客户端量身定制的。

假设您想基于平台的2.3.5.RELEASE版本生成一个“my-project.zip”项目,并使用webdevtools依赖项(请记住,这两个 ID 显示在服务的“功能”中)

$ curl -G https://127.0.0.1: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://127.0.0.1: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,则省略版本。

  • 如果此依赖项需要兼容版本范围(或最小值或最大值),请将其添加为 链接版本

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

如果您的依赖项需要特定版本的平台,或者不同版本的平台需要不同版本的依赖项,则有几种机制可以配置它。

最简单的方法是在依赖项声明中添加 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"

在此示例中,从与平台 1.4.0 版本兼容的版本开始,foo 的构件更改为 foo-spring-boot-starter。此映射指示如果选择平台的 1.3.x 版本,则构件 ID 应设置为 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. 配置快照存储库

如果默认存储库(通常为 Maven Central)不包含构件,则依赖项或 BOM 可能需要使用特定存储库。通常,声明它的最佳位置是 BOM 配置中,但如果没有 BOM,则可以将其放在依赖项本身中。您还可以使用平台 版本映射 覆盖依赖项或 BOM 的默认存储库。

9.5. 配置自定义父 POM

对于 Maven 项目,您可以按如下方式配置自定义父 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. 确保常规依赖项包含基本启动器

如果依赖项不能独立存在(特别是如果它不依赖于现有的 Spring Boot 启动器),则可以将其标记为“非启动器”。

initializr:
  dependencies:
    - name: Stuff
      content:
        - name: Lib
          id: lib
          groupId: com.acme
          artifactId: lib
          starter: false

当生成的项目仅包含设置了此标志的依赖项时,也会添加基本 Spring Boot 启动器。

9.7. 在组中共享公共依赖项设置

依赖项组是用户界面实现的提示,用于在用户选择依赖项时将它们组合在一起。它也是在依赖项之间共享设置的便捷方式,因为每个依赖项都继承所有设置。组中最常见的设置是 groupIdcompatibilityRangebom

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 版本之前定义的原始格式。V2 是从元数据 2.2 版本开始与 V1 一起提供的 SemVer 格式。为了提供向后兼容的内容,应配置每种格式的版本范围,以便可以相应地进行转换。

假设实例仅支持 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. 缓存配置

如果您使用此服务,您会注意到日志中有很多条目,消息为 api.spring.io/projects/spring-boot/releases 获取引导元数据。为了避免过于频繁地检查最新的 Spring Boot 版本,您应该在服务上启用缓存。

如果您愿意使用 JCache(JSR-107)实现,则 Spring Initializr 具有对请求的缓存的自动配置。默认情况下,服务元数据缓存配置了到期策略,允许条目在缓存中保留 10 分钟。

缓存使用自动配置的 JCacheManagerCustomizer 创建,顺序为 0,并且仅在它们不存在时创建。您可以使用较低 @Order 的相同类型的 bean 来覆盖某些配置以满足您的特定需求。

添加 javax.cache:cache-api 和您喜欢的 JCache 实现,只需通过在您的 @SpringBootApplication 中添加 @EnableCaching 来启用缓存即可。例如,您可以使用 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,则应自行配置缓存。以下是应用程序使用的缓存(每个缓存都需要一些配置才能使其工作)

表 1. 缓存配置
缓存名称 描述

initializr.metadata

缓存服务的完整元数据。当元数据过期时,它会再次完全解析(这可能包括确定最新平台版本的网络调用)。相应地调整过期设置。

initializr.dependency-metadata

缓存特定于依赖项的元数据。

initializr.templates

缓存用于生成项目的模板。

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.0foo/1.2.0)。

11.1. 服务功能

任何第三方客户端都可以通过使用以下 Accept 标头在根 URL 上发出 GET 请求来检索服务的 功能: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"
  }
}

当前功能如下

  • 项目依赖项:这些实际上是启动器,或者实际上是我们可能想要添加到项目中的任何依赖项。

  • 项目类型:这些定义可以在此服务上调用的操作以及它将生成的内容的描述(例如,包含预配置 Maven 项目的 zip 文件)。每种类型可能还有一个或多个标记,进一步定义它生成的内容。

  • 打包:要生成的项目类型。这仅仅是向负责生成项目的组件提供提示(例如,生成可执行的jar项目)。

  • Java 版本:支持的 Java 版本

  • 语言:要使用的语言(例如 Java)

  • 引导版本:要使用的平台版本

  • 其他基本信息,例如:groupIdartifactIdversionnamedescriptionpackageName

每个顶级属性(即功能)都具有标准格式

  • 一个type属性,用于定义属性的语义(见下文)。

  • 一个default属性,用于定义默认值或默认值的引用。

  • 一个values属性,用于定义可接受的值集(如果有)。这可以是分层的(values包含在values中)。values数组中的每个项目都可以具有idnamedescription

支持以下type属性

  • text:定义一个没有选项的简单文本值。

  • single-select:定义一个从指定选项中选择的值。

  • hierarchical-multi-select:定义一个分层的值集(values in 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. 项目依赖项

依赖项通常是启动器模块的坐标,但它也可以只是一个常规依赖项。典型的依赖项结构如下所示

{
  "name": "Display name",
  "id": "org.acme.project:project-starter-foo",
  "description": "What starter foo does"
}

名称用作显示名称,显示在远程客户端使用的任何 UI 中。id 可以是任何内容,因为实际的依赖项定义是通过配置定义的。如果未定义 id,则会使用依赖项的groupIdartifactId构建一个默认 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-TypeContent-Disposition标头的响应标头。

请注意,每个 id 都具有相关的符合 HAL 规范的链接,可用于根据模板变量生成正确的 URI。顶级type与任何其他属性一样,都具有default属性,该属性是选择服务认为是良好默认值的提示。

action属性定义客户端应联系的端点,以实际生成该类型的项目(如果您无法使用符合 HAL 规范的 url)。

tags对象用于对项目类型进行分类并为第三方客户端提供提示。例如,build标签定义了项目将使用的构建系统,而format标签定义了生成内容的格式(即,此处是完整的项目与构建文件)。请注意,回复的Content-type标头提供了其他元数据。

11.1.3. 打包

packaging元素定义应生成的项目类型。

打包示例
{
  "id" : "jar",
  "name" : "Jar"
}

此元素的明显值是jarwar

11.1.4. Java 版本

javaVersion元素提供项目可能使用的 Java 版本列表

Java 示例
{
  "id" : "1.6",
  "name" : "1.6"
}

11.1.5. 语言

language元素提供项目可能使用的语言列表

语言示例
{
  "id" : "groovy",
  "name" : "Groovy"
}

11.1.6. 平台版本

bootVersion元素提供可用平台版本的列表

平台版本示例
{
  "id" : "2.5.0-SNAPSHOT",
  "name" : "Latest SNAPSHOT"
}

11.2. 默认值

每个顶级元素都有一个default属性,应将其用作提示,以便在相关的 UI 组件中提供默认值。

12. 使用存根

Spring Initializr 项目发布了WireMock存根,用于项目中测试的所有 JSON 响应。如果您正在为 Spring Initializr 服务编写客户端,则可以使用这些存根来测试您自己的代码。您可以使用原始 Wiremock API 或Spring Cloud Contract的一些功能来使用它们。

WireMock 是一款嵌入式 Web 服务器,它分析传入的请求并根据匹配某些规则(例如,特定标头值)选择存根响应。因此,如果您向其发送与其中一个存根匹配的请求,它将向您发送响应,就像它是真正的 Initializr 服务一样,您可以使用它来进行客户端的全栈集成测试。

12.1. 使用 WireMock 与 Spring Boot

12.1.1. 从类路径加载存根

在您的项目中使用存根的一种便捷方法是添加测试依赖项

<dependency>
    <groupId>io.spring.initializr</groupId>
    <artifactId>initializr-web</artifactId>
    <classifier>stubs</classifier>
    <version>0.20.1</version>
    <scope>test</scope>
</dependency>

然后从类路径中提取存根。在 Spring Boot 应用程序中,使用 Spring Cloud Contract,您可以启动 WireMock 服务器并在其中注册所有存根,如下面的基于 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. 使用存根运行器

或者,您可以配置存根运行器查找工件,使用不同的 Spring Cloud Contract 依赖项:spring-cloud-starter-contract-stub-runner。以下示例将在必要时自动下载 Spring Initializr 存根的定义版本(因此您不需要将存根声明为依赖项)

<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 元数据的存根(metadataWithCurrentAcceptHeader.json)。

12.2. 存根的名称和路径

存根以 jar 文件的形式(在“**/mappings”下)布局,可以通过设置其文件源即可被 WireMock 使用。各个存根的名称与在 Spring Initializr 项目中生成它们的测试用例的函数名称相同。例如,MainControllerIntegrationTests中有一个测试用例“metadataWithV2AcceptHeader”,它对当接受标头为application/vnd.initializr.v2.1+json时的响应进行断言。响应记录在存根中,如果使用了与 Spring Initializr 测试用例中相同的值并且客户端使用相同的标头和请求参数,它将在 WireMock 中匹配。函数名称通常总结了这些值是什么。

存根运行器以及上述示例中的@AutoConfigureWireMock将所有存根加载到 WireMock 中,因此您不必知道存根的名称。但是,您也可以逐个注册存根,在这种情况下,扫描存根 jar 并将文件名与测试函数进行比较会有所帮助。例如,如果您查看存根 jar,您将看到一个名为metadataWithV2AcceptHeader.json的文件,并且在 initializr-web 项目中,有一个名为metadataWithV2AcceptHeader的测试函数生成了它。