响应式基础设施

本节介绍使用 Spring Vault 的响应式编程支持的基本信息。

什么是响应式编程?

简单来说,响应式编程是关于非阻塞的、异步的和事件驱动的应用程序,它们只需要少量线程即可进行垂直扩展(即在 JVM 内),而不是水平扩展(即通过集群)。

响应式应用程序的一个关键方面是背压的概念,这是一种机制,用于确保生产者不会压垮消费者。例如,在一个从数据库扩展到 HTTP 响应的响应式组件管道中,当 HTTP 连接太慢时,数据存储库也可以减速或完全停止,直到网络容量释放。

响应式 Vault 客户端

Spring Vault 的响应式客户端支持构建在可组合身份验证步骤和 Spring 的函数式WebClient(通过 Reactor Netty 或 Jetty)之上,后者都具有完全非阻塞的、事件驱动的 HTTP 客户端。

它公开VaultTokenSupplier 作为VaultToken 的提供程序来认证 HTTP 请求,并公开ReactiveVaultOperations 作为主要入口点。VaultEndpointClientOptionsSSL 的核心配置在各种客户端实现中被重复使用。

ReactiveVaultTemplate(位于 `org.springframework.vault.core` 包中)是 Spring 响应式 Vault 支持的核心类,提供丰富的功能集来与 Vault 交互。该模板提供方便的操作来读取、写入和删除 Vault 中的数据,并提供域对象和 Vault 数据之间的映射。

配置完成后,ReactiveVaultTemplate 是线程安全的,可以在多个实例中重复使用。

Vault 文档和域类之间的映射是通过委托给 WebClient 及其编解码器来完成的。

ReactiveVaultTemplate 类实现了接口ReactiveVaultOperations。尽可能地,ReactiveVaultOperations 上的方法都以 Vault API 上可用的方法命名,以便熟悉 Vault API 和 CLI 的现有 Vault 开发人员能够轻松上手。例如,你会找到诸如“write”、“delete”和“read”之类的 方法。设计目标是尽可能简化在使用 Vault API 和ReactiveVaultOperations 之间的转换。这两个 API 之间的一个主要区别是ReactiveVaultOperations 可以传递域对象,而不是 JSON 键值对。

引用ReactiveVaultTemplate 实例上的操作的首选方法是通过其接口ReactiveVaultOperations

对于ReactiveVaultTemplate未明确公开的功能,可以使用几种执行回调方法之一来访问底层 API。执行回调将为您提供对 WebClient 对象的引用。有关更多信息,请参阅执行回调部分。

现在让我们来看一些如何在 Spring 容器的上下文中使用 Vault 的示例。

注册和配置 Spring Vault bean

使用 Spring Vault 不需要 Spring Context。但是,在托管上下文内注册的ReactiveVaultTemplateVaultTokenSupplier 实例将参与 Spring IoC 容器提供的生命周期事件。这对于在应用程序关闭时释放活动的 Vault 会话非常有用。您还可以从在整个应用程序中重复使用相同的ReactiveVaultTemplate 实例中获益。

Spring Vault 带有一个支持配置类,该类提供可在 Spring 上下文中使用的 bean 定义。应用程序配置类通常扩展自AbstractVaultConfiguration,并且需要提供特定于环境的其他详细信息。

扩展AbstractVaultConfiguration 需要实现 `VaultEndpoint vaultEndpoint()` 和 ClientAuthentication clientAuthentication() 方法。

示例 1. 使用基于 Java 的 bean 元数据注册 Spring Vault 对象
@Configuration
public class AppConfig extends AbstractReactiveVaultConfiguration {

    /**
     * Specify an endpoint for connecting to Vault.
     */
    @Override
    public VaultEndpoint vaultEndpoint() {
        return new VaultEndpoint();                            (1)
    }

    /**
     * Configure a client authentication.
     * Please consider a more secure authentication method
     * for production use.
     */
    @Override
    public ClientAuthentication clientAuthentication() {
        return new TokenAuthentication("…");                   (2)
    }
}
1 创建一个新的VaultEndpoint,默认指向https://127.0.0.1:8200
2 此示例使用TokenAuthentication 快速入门。有关支持的身份验证方法的详细信息,请参见[vault.core.authentication]

会话管理

Spring Vault 需要令牌来验证 Vault 请求。有关身份验证的详细信息,请参见[vault.core.authentication]。响应式客户端需要一个非阻塞令牌提供程序,其约定在VaultTokenSupplier中定义。令牌可以是静态的,也可以通过声明的身份验证流程获得。不应该在每次经过身份验证的 Vault 交互中都进行 Vault 登录,而应该在整个会话中保留会话令牌。此方面由实现ReactiveSessionManager的会话管理器处理,例如ReactiveLifecycleAwareSessionManager

执行回调

所有 Spring 模板类的一个常见设计特征是,所有功能都路由到模板的 execute 回调方法之一。这有助于确保一致地执行异常和任何可能需要的资源管理。虽然在 JDBC 和 JMS 中比在 Vault 中更需要这样做,但它仍然提供了一个用于访问和记录的单一位置。因此,使用 execute 回调是访问 Vault API 以执行我们尚未在ReactiveVaultTemplate上公开为方法的不常见操作的首选方法。

以下是 execute 回调方法的列表。

  • <T> T doWithVault (Function<WebClient, ? extends T> clientCallback) 组合给定WebClient的响应式序列,允许在没有会话上下文的情况下与 Vault 交互。

  • <T> T doWithSession (Function<WebClient, ? extends T> clientCallback) 组合给定WebClient的响应式序列,允许在经过身份验证的会话中与 Vault 交互。

这是一个使用回调初始化 Vault 的示例

reactiveVaultOperations.doWithVault(webClient -> {

    return webClient.put()
                    .uri("/sys/init")
                    .syncBody(request)
                    .retrieve()
                    .toEntity(VaultInitializationResponse.class);
});