Platform

Quarkus 扩展生态系统由社区(包括 Quarkus 核心开发团队)开发并维护的 Quarkus 扩展组成。尽管 Quarkus 生态系统(有时也称为“Quarkus 宇宙”)包含了所有开发的 Quarkus 扩展,但它也有一个 Quarkus 平台的概念。

Quarkus Platform

Quarkus 平台的基本承诺是该平台组成的任何 Quarkus 扩展组合均可在同一应用程序中使用,而不会彼此造成任何冲突。创建其 Quarkus 平台的每个组织可能会制定它们自己的标准,以将扩展纳入该平台以及保证已接受的扩展之间的兼容性的方法。

Quarkus Platform Artifacts

每个 Quarkus 平台均定义为几个工件。

Quarkus Platform BOM

每个 Quarkus 平台应提供 Maven BOM 工件,该工件

  • 导入选定的 io.quarkus:quarkus-bom 版本(平台 BOM 可能在最后扁平化,但它必须基于某种 io.quarkus:quarkus-bom 版本)

  • 包括该平台组成的所有 Quarkus 扩展工件(运行时和部署时工件)

  • 包括所有必要的第三方工件,它们将平台扩展的传递依赖版本对齐,以保证它们之间的兼容性

  • 包括 platform JSON descriptor 工件

  • 可能包括 platform configuration properties 工件

要包含来自 Quarkus 平台的扩展的 Quarkus 应用程序将导入 Quarkus 平台 BOM。

Quarkus Platform Descriptor

Quarkus 平台描述符是一个 JSON 工件,可为 Quarkus 工具提供有关该平台及其扩展的信息。例如 [role="bare"][role="bare"]https://code.quarkus.io/ 和 Quarkus 命令行工具根据用户的请求参考此描述符来列示、添加和移除项目中的扩展。此工件还用作 Quarkus 平台标识符。当 Quarkus 工具需要识别项目中使用的 Quarkus 平台时,它们将分析该项目的依赖版本约束(根据 Maven 术语为 dependencyManagement 部分中托管依赖的有效列表),搜索它们中的平台描述符工件。鉴于平台描述符包含在 Quarkus 平台 BOM 中,因此每个 Quarkus 应用程序均会从导入的平台 BOM(作为依赖版本约束(Maven 中的托管依赖)继承平台描述符工件。

为了能够在项目的依赖约束中轻松识别 Quarkus 平台描述符,平台描述符 Maven 工件坐标应遵循以下命名约定:

  • 描述符工件的 groupId 应与相应 Quarkus 平台 BOM 的 groupId 匹配;

  • 描述符工件的 artifactId 应为相应 Quarkus 平台 BOM 的 artifactId 和后缀 -quarkus-platform-descriptor 的组合;

  • 描述符工件的 classifier 应与该相应 Quarkus 平台 BOM 的 version 匹配;

  • 描述符工件的 type 应为 json

  • 描述符工件的 version 应与相应 Quarkus 平台 BOM 的 version 匹配。

它将作为字符串 <platform-bom-groupId>:<platform-bom-artifactId>-quarkus-platform-descriptor:<platform-version>:json:<platform-version> 出现

例如,Quarkus BOM 的描述符的坐标 io.quarkus.platform:quarkus-bom::pom:1.2.3 将为 io.quarkus.platform:quarkus-bom-quarkus-platform-descriptor:1.2.3:json:1.2.3。而对于使用 BOM org.acme:acme-bom::pom:555 定义的自定义 Quarkus 平台,它将为 org.acme:acme-bom-quarkus-platform-descriptor:555:json:555.might

匹配平台版本的分类器起初似乎很让人困惑。但这正是将描述符变成平台真正“指纹”的方式。在 Maven 和 Gradle 中,通过合并所有导入的 BOM 以及在当前项目中单独指定的版本约束(或管理的依赖项)以及它的父项来获取依赖项版本约束的有效集合(或管理的依赖项)。构件 classifier 是依赖项 ID 的一部分,可以表示为 groupId:artifactId:classifier:type。这意味着如果项目导入几个 BOM,例如 org.apple:apple-bom::pom:1.0org.orange:orange-bom::pom:1.0,并且这两个 BOM 中的每一个都导入一个不同的版本 io.quarkus.platform:quarkus-bom::pom,那么 Quarkus 工具将能够检测到这一事实,并告知用户,因为它 *might*不是一个安全的组合。如果描述符构件不包含包含平台版本的分类器,那么工具将无法检测到同一个项目中不同版本的同一个平台的潜在不兼容组合。

平台描述符通常使用 Maven 插件生成,例如:

<plugin>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-platform-descriptor-json-plugin</artifactId>
  <version>${quarkus.version}</version> 1
  <executions>
    <execution>
      <phase>process-resources</phase>
      <goals>
        <goal>generate-extensions-json</goal> 2
      </goals>
    </execution>
  </executions>
  <configuration>
    <bomGroupId>${quarkus.platform.group-id}</bomGroupId> 3
    <bomArtifactId>${quarkus.platform.artifact-id}</bomArtifactId> 4
    <bomVersion>${quarkus.platform.version}</bomVersion> 5
    <overridesFile>${overridesfile}</overridesFile> 6
    <resolveDependencyManagement>true</resolveDependencyManagement> 7
  </configuration>
</plugin>
1 quarkus-platform-descriptor-json-plugin 的版本
2 generate-extensions-json 是生成平台描述符的目标
3 平台 BOM 的 groupId
4 平台 BOM 的 artifactId
5 平台 BOM 的 version
6 此参数是可选的,它允许覆盖平台描述符生成时来自每个运行时扩展构件中的 Quarkus 扩展描述符中的一些元数据
7 此参数也是可选的,默认为 false。如果平台 BOM is not generatedis not flattened,则必须将其设置为 true。例如,io.quarkus:quarkus-bom 便是如此。

Quarkus Platform Properties

Quarkus 平台可以为某些配置选项提供其自己的默认值。

Quarkus 正在使用 SmallRye Config 来配置应用程序配置。Quarkus 平台可以用作由应用程序的 application.properties 支配的配置源层次结构中的另一个配置源。

为了提供特定于平台的默认值,该平台需要在其 BOM 中包含一个属性构件的依赖关系版本约束,其坐标遵循以下命名约定:

  • 属性构件的 groupId 应与相应的 Quarkus 平台 BOM 的 groupId 匹配;

  • 属性构件的 artifactId 应为相应的 Quarkus 平台 BOM 的 artifactId 外加后缀 -quarkus-platform-properties

  • 描述符构件的 classifier 应留空/为 null;

  • 描述符构件的 type 应为 properties

  • 描述符工件的 version 应与相应 Quarkus 平台 BOM 的 version 匹配。

属性构件本身应为传统的 properties 文件,该文件将加载到 java.util.Properties 类的实例中。

在这一点上,平台属性只能为受限制的一组配置选项提供默认值。平台属性文件中的属性名称必须以后缀 platform. 为前缀。

希望让自己的配置选项特定于平台的扩展开发者应当将自己的默认值设置为以后缀 platform. 开头的属性。示例如下:

package io.quarkus.deployment.pkg;

@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
@ConfigMapping(prefix = "quarkus")
public interface NativeConfig {

    /**
     * The docker image to use to do the image build
     */
    @WithDefault("${platform.quarkus.native.builder-image}")
    String builderImage();
}

在这种情况下,quarkus.native.builder-image 的默认值将由平台提供。当然,用户仍然可以将其 application.properties 中的 quarkus.native.builder-image 设置为所需的。但是,如果用户未自定义,则默认值将来自平台属性。示例的上方平台属性文件将包含:

platform.quarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:{mandrel-flavor}

还有一个 Maven 插件目标,用于验证平台属性内容及工件坐标,同时检查平台属性工件是否存在于平台的 BOM 中。这是一个示例插件配置:

<plugin>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-platform-descriptor-json-plugin</artifactId>
  <version>${quarkus.version}</version>
  <executions>
    <execution>
      <phase>process-resources</phase>
      <goals>
        <goal>platform-properties</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Merging Quarkus Platform Properties

如果应用程序导入多个 Quarkus 平台,并且这些平台包含各自的平台属性工件,那么这些平台属性工件的内容将合并,形成一组属性,用于应用程序构建。属性工件合并的顺序将对应于它们在应用程序依赖版本约束列表中出现的顺序(以 Maven 术语而言,这将对应于应用程序管理依赖的有效列表,即扁平化的 managedDependencies POM 部分)。

先前找到的属性工件的内容将高于应用程序依赖约束中之后找到的内容!

这意味着,如果某个平台需要覆盖其基于平台中定义的某个属性值,它需要在其 BOM 的 managedDependencies 部分中包含其平台属性工件,然后再导入基础平台。

例如,我们假设 org.acme:acme-quarkus-bom 平台通过导入其 BOM 来扩展 io.quarkus:quarkus-bom 平台。如果 org.acme:acme-quarkus-bom 平台将覆盖包含在 io.quarkus:quarkus-bom 中的 io.quarkus:quarkus-bom-quarkus-platform-properties 中定义的某个属性,那么 org.acme:acme-quarkus-bom 需要这样构成

  <!-- skipped content -->

  <artifactId>acme-quarkus-bom</artifactId>
  <name>Acme - Quarkus - BOM</name>
  <packaging>pom</packaging>

  <dependencyManagement>
    <dependencies>
      <!-- Acme Quarkus platform properties -->
      <dependency>
        <groupId>org.acme</groupId>
        <artifactId>acme-quarkus-bom-quarkus-platform-properties</artifactId>
        <type>properties</type>
        <version>${project.version}</version>
      </dependency>

      <!-- The base Quarkus BOM -->
      <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-bom</artifactId>
        <version>${quarkus.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

  <!-- skipped content -->

这样,org.acme:acme-quarkus-bom 平台属性将出现在 io.quarkus:quarkus-bom 属性提供的属性之前,从而在构建时优先使用。