Reactive Infrastructure

本部分涵盖使用 Spring Vault 的响应式编程支持的基本信息。

What is Reactive Programming?

简单地说,响应式编程是关于非阻塞应用程序的,这些应用程序是异步的、事件驱动的,并且需要少量的线程才能垂直扩展(例如在 JVM 内),而不是水平扩展(例如通过集群)。

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

Reactive Vault Client

Spring Vault 的反应式客户端支持构建在 composable authentication steps 和 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 上的方法命名,使得 API 对习惯于使用 API 和 CLI 的现有 Vault 开发者来说很熟悉。例如,你会找到诸如“write”、“delete”和“read”这样的方法。设计目标是尽可能轻松地在 Vault API 和 ReactiveVaultOperations 之间进行转换。两个 API 之间的一个主要区别是 ReactiveVaultOperations 可以传递域对象而不是 JSON 键值对。

引用 ReactiveVaultTemplate 实例上操作的首选方式是通过其界面 ReactiveVaultOperations

ReactiveVaultTemplate 中明确未公开的功能,你可以使用几个 execute 回调方法之一来访问底层 API。execute 回调将为你提供对 WebClient 对象的引用。请参阅 Execution Callbacks 部分以了解更多信息。

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

Registering and configuring Spring Vault beans

使用 Spring Vault 不需要 Spring 上下文。但是,在受管上下文中注册的 ReactiveVaultTemplateVaultTokenSupplier 的实例将参与 Spring IoC 容器提供的 {spring-framework-docs}core.html#beans-factory-nature[生命周期事件]。这有助于在应用程序关闭时释放活动 Vault 会话。您还可以受益于在整个应用程序中重复使用相同的 ReactiveVaultTemplate 实例。

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

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

Example 1. Registering Spring Vault objects using Java based bean metadata
@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://localhost:8200
2 此示例使用 TokenAuthentication 快速入门。请参阅 [vault.core.authentication] 了解受支持的身份验证方法的详细信息。

Session Management

Spring Vault 需要一个令牌来验证 Vault 请求。请参阅 [vault.core.authentication] 中关于验证的详细信息。反应式客户端需要一个非阻塞的令牌供应商,其协定在 VaultTokenSupplier 中定义。令牌可以是静态的,也可以通过 declared authentication flow 获得。Vault 登录不应该发生在每次验证的 Vault 交互中,但会话令牌应该在会话中保持。这个方面是由实现 ReactiveSessionManager(如 ReactiveLifecycleAwareSessionManager)的会话管理器处理的。

Execution callbacks

所有 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);
});