跳到主要内容

Spring Cloud Config 客户端

DeepSeek V3 中英对照 Spring Cloud Config Client

Spring Cloud 配置客户端

Spring Boot 应用程序可以立即利用 Spring Config Server(或应用程序开发者提供的其他外部属性源)。它还会获取一些与 Environment 变更事件相关的额外有用功能。

Spring Boot 配置数据导入

Spring Boot 2.4 引入了一种通过 spring.config.import 属性导入配置数据的新方式。现在这是绑定到 Config Server 的默认方式。

要在 application.properties 中可选地连接到配置服务器,请设置以下内容:

spring.config.import=optional:configserver:
properties

这将连接到默认位置为 [http://localhost:8888](http://localhost:8888) 的配置服务器。如果移除 optional: 前缀,当配置客户端无法连接到配置服务器时,将会导致失败。要更改配置服务器的位置,可以设置 spring.cloud.config.uri,或者在 spring.config.import 语句中添加 URL,例如 spring.config.import=optional:configserver:http://myhost:8888。在导入属性中指定的位置优先于 uri 属性。

Spring Boot 配置数据通过两个步骤来解析配置。首先,它使用 default 配置文件加载所有配置。这使得 Spring Boot 能够收集所有可能激活任何附加配置文件的配置。在收集了所有激活的配置文件后,它将为这些激活的配置文件加载任何额外的配置。因此,你可能会看到向 Spring Cloud Config Server 发出多个请求以获取配置。这是正常的,并且是 Spring Boot 在使用 spring.config.import 时加载配置的副作用。在 Spring Cloud Config 的早期版本中,只会发出一个请求,但这意味着你无法从 Config Server 获取的配置中激活配置文件。现在,仅使用 default 配置文件的额外请求使得这一点成为可能。

备注

对于通过 spring.config.import 导入的 Spring Boot 配置数据方法,不需要 bootstrap 文件(properties 或 yaml)。

配置优先引导

要使用传统的 bootstrap 方式连接到 Config Server,必须通过属性或 spring-cloud-starter-bootstrap starter 启用 bootstrap。该属性为 spring.cloud.bootstrap.enabled=true。它必须设置为系统属性或环境变量。一旦启用了 bootstrap,任何在类路径上具有 Spring Cloud Config Client 的应用程序都将按以下方式连接到 Config Server:当配置客户端启动时,它会绑定到 Config Server(通过 spring.cloud.config.uri bootstrap 配置属性),并使用远程属性源初始化 Spring Environment

这种行为的结果是,所有希望使用 Config Server 的客户端应用程序都需要一个 bootstrap.yml 文件(或环境变量),并在其中设置 spring.cloud.config.uri 为服务器地址(默认值为 "http://localhost:8888")。

发现首次查找

注意

除非你使用 配置优先引导,否则你需要在配置属性中包含一个带有 optional: 前缀的 spring.config.import 属性。例如,spring.config.import=optional:configserver:

如果你使用 DiscoveryClient 实现,比如 Spring Cloud Netflix 和 Eureka 服务发现或 Spring Cloud Consul,你可以让 Config Server 注册到发现服务中。

如果你更倾向于使用 DiscoveryClient 来定位 Config Server,可以通过设置 spring.cloud.config.discovery.enabled=true 来实现(默认值为 false)。例如,在使用 Spring Cloud Netflix 时,你需要定义 Eureka 服务器的地址(例如,在 eureka.client.serviceUrl.defaultZone 中设置)。使用此选项的代价是在启动时需要进行一次额外的网络往返,以定位服务注册。好处是,只要 Discovery Service 是一个固定点,Config Server 可以改变其坐标。默认的服务 ID 是 configserver,但你可以在客户端通过设置 spring.cloud.config.discovery.serviceId 来更改它(在服务器端,可以通过通常的服务设置方式,例如设置 spring.application.name 来更改)。

所有的发现客户端实现都支持某种元数据映射(例如,对于 Eureka,我们有 eureka.instance.metadataMap)。Config Server 的一些附加属性可能需要在其服务注册元数据中进行配置,以便客户端可以正确连接。如果 Config Server 使用 HTTP Basic 进行安全保护,你可以将凭据配置为 userpassword。此外,如果 Config Server 有上下文路径,你可以设置 configPath。例如,以下 YAML 文件适用于作为 Eureka 客户端的 Config Server:

eureka:
instance:
...
metadataMap:
user: osufhalskjrtl
password: lviuhlszvaorhvlo5847
configPath: /config
yaml

使用 Eureka 和 WebClient 进行首次发现引导

如果你使用来自 Spring Cloud Netflix 的 Eureka DiscoveryClient,并且还想使用 WebClient 而不是 Jersey 或 RestTemplate,你需要在你的类路径中包含 WebClient,同时设置 eureka.client.webclient.enabled=true

配置客户端快速失败

在某些情况下,如果服务无法连接到 Config Server,您可能希望服务的启动失败。如果这是期望的行为,可以设置引导配置属性 spring.cloud.config.fail-fast=true,以使客户端在遇到异常时停止启动。

备注

要使用 spring.config.import 实现类似的功能,只需省略 optional: 前缀即可。

配置客户端重试

如果你预计配置服务器在应用程序启动时可能偶尔不可用,你可以让应用程序在失败后继续尝试。首先,你需要设置 spring.cloud.config.fail-fast=true。然后,你需要在类路径中添加 spring-retryspring-boot-starter-aop。默认行为是重试六次,初始退避间隔为 1000 毫秒,后续退避的指数乘数为 1.1。你可以通过设置 spring.cloud.config.retry.* 配置属性来配置这些属性(以及其他属性)。要使用随机指数退避策略,请将 spring.cloud.config.retry.useRandomPolicy 设置为 true

备注

spring.cloud.config.retry.useRandomPolicytrue 时,即使使用随机指数退避策略,max-attemptsinitial-intervalmax-intervalmultiplier 属性仍然会生效。关于它们如何使用的详细信息可以在 Spring Retry 中的 ExponentialRandomBackOffPolicyExponentialBackOffPolicy 中找到。

提示

要完全控制重试行为并且正在使用传统引导程序,请添加一个类型为 RetryOperationsInterceptor@Bean,其 ID 为 configServerRetryInterceptor。Spring Retry 提供了一个 RetryInterceptorBuilder,支持创建该拦截器。

配置客户端重试与 spring.config.import

Retry 可以与 Spring Boot 的 spring.config.import 语句一起使用,并且普通的属性也能正常工作。然而,如果导入语句位于配置文件中,例如 application-prod.properties,那么你需要采用不同的方式来配置重试。配置需要作为 URL 参数放在导入语句上。

spring.config.import=configserver:http://configserver.example.com?fail-fast=true&max-attempts=10&max-interval=1500&multiplier=1.2&initial-interval=1100"
properties

这将设置 spring.cloud.config.fail-fast=true(注意上面缺少的前缀)以及所有可用的 spring.cloud.config.retry.* 配置属性。

定位远程配置资源

Config Service 从 /{application}/{profile}/{label} 提供属性源,其中客户端应用中的默认绑定如下:

  • "application" = ${spring.application.name}

  • "profile" = ${spring.profiles.active} (实际上是 Environment.getActiveProfiles())

  • "label" = "master"

备注

在设置属性 ${spring.application.name} 时,请不要在应用程序名称前加上保留字 application-,以避免解析正确的属性源时出现问题。

你可以通过设置 spring.cloud.config.*(其中 *nameprofilelabel)来覆盖所有这些配置。label 对于回滚到以前的配置版本非常有用。在默认的 Config Server 实现中,它可以是 git 标签、分支名称或提交 ID。标签也可以以逗号分隔的列表形式提供。这种行为在处理功能分支时非常有用。例如,你可能希望将配置标签与你的分支对齐,但使其成为可选项(在这种情况下,使用 spring.cloud.config.label=myfeature,develop)。

请求多个标签

在 Spring Cloud Config 4.2.0 之前,如果你将 spring.cloud.config.label 设置为一个以逗号分隔的标签列表,Config Client 会通过向 Config Server 发出请求来尝试每个标签,直到找到一个可用的标签。这意味着如果第一个标签被找到,后续的标签将不会被尝试。

自 Spring Cloud Config 4.2.0 起,如果你将 spring.cloud.config.label 设置为一个逗号分隔的标签列表 并且 设置了 spring.cloud.config.send-all-labels,Config Client 将会向 Config Server 发出一个包含逗号分隔标签列表的请求,如果 CONFIG SERVER 使用的是 4.2.0 或更高版本,它将返回一个包含所有标签属性源的响应。

备注

spring.cloud-config.send-all-labels 设置为 true,将 spring.cloud.config.label 设置为逗号分隔的标签列表,并在 4.2.0 之前的 Config Server 版本中使用时,会导致意外行为,因为 Config Server 会尝试查找与逗号分隔列表值匹配的标签,而不会尝试拆分这些标签。

通过在一次请求中发送所有标签,可以减少对配置服务器的请求次数。

spring.cloud.config.send-all-labels 默认设置为 false,因此旧的行为仍然是默认行为,同时也保持了与旧版本 Config Server 的兼容性。

为配置服务器指定多个 URL

为了确保高可用性,当您部署了多个 Config Server 实例,并且预期其中一个或多个实例可能偶尔不可用或无法响应请求时(例如 Git 服务器宕机),您可以指定多个 URL(在 spring.cloud.config.uri 属性下以逗号分隔的列表),或者让所有实例注册到像 Eureka 这样的服务注册中心(如果使用 Discovery-First Bootstrap 模式)。

spring.cloud.config.uri 下列出的 URL 会按照列出的顺序依次尝试。默认情况下,Config Client 会尝试从每个 URL 获取属性,直到某个尝试成功为止,以确保高可用性。

然而,如果您希望仅在配置服务器未运行(即应用程序已退出)或发生连接超时时确保高可用性,请将 spring.cloud.config.multiple-uri-strategy 设置为 connection-timeout-only。(spring.cloud.config.multiple-uri-strategy 的默认值为 always。)例如,如果配置服务器返回 500(内部服务器错误)响应,或者配置客户端从配置服务器接收到 401(由于凭据错误或其他原因),配置客户端不会尝试从其他 URL 获取属性。400 错误(可能不包括 404)表示用户问题而非可用性问题。请注意,如果配置服务器设置为使用 Git 服务器,并且对 Git 服务器的调用失败,则可能会发生 404 错误。

可以在一个 spring.config.import 键下指定多个位置,而不是使用 spring.cloud.config.uri。这些位置将按照定义的顺序进行处理,后导入的配置将优先。然而,如果 spring.cloud.config.fail-fast 设置为 true,当第一次调用 Config Server 失败时,Config Client 将直接失败。如果 fail-fast 设置为 false,它将尝试所有 URL,直到有一个调用成功为止,无论失败的原因是什么。(当在 spring.config.import 下指定 URL 时,spring.cloud.config.multiple-uri-strategy 不适用。)

如果你在配置服务器上使用 HTTP 基本安全认证,目前只有在将凭据嵌入到 spring.cloud.config.uri 属性下指定的每个 URL 中时,才能支持每个配置服务器的认证凭据。如果你使用任何其他类型的安全机制,目前无法支持每个配置服务器的认证和授权。

配置超时

如果你想配置超时阈值:

  • 读取超时可以通过使用属性 spring.cloud.config.request-read-timeout 来配置。

  • 连接超时可以通过使用属性 spring.cloud.config.request-connect-timeout 来配置。

配置字符集

如果你想配置服务器应提供的资源的特定字符集,需要通过 charset 来应用它。

spring:
cloud:
config:
charset: UTF-8

字符集配置属性定义为 java.nio.charset.Charset

安全性

如果您在服务器上使用 HTTP Basic 安全机制,客户端需要知道密码(以及用户名,如果它不是默认值)。您可以通过配置服务器的 URI 或通过单独的用户名和密码属性来指定用户名和密码,如下例所示:

spring:
cloud:
config:
uri: https://user:secret@myconfig.mycompany.com
yaml

以下示例展示了传递相同信息的另一种方式:

spring:
cloud:
config:
uri: https://myconfig.mycompany.com
username: user
password: secret
yaml

spring.cloud.config.passwordspring.cloud.config.username 的值会覆盖 URI 中提供的任何内容。

如果你在 Cloud Foundry 上部署你的应用程序,提供密码的最佳方式是通过服务凭证(例如在 URI 中,因为它不需要在配置文件中)。以下示例在本地和名为 configserver 的 Cloud Foundry 用户提供的服务上都可以工作:

spring:
cloud:
config:
uri: ${vcap.services.configserver.credentials.uri:http://user:password@localhost:8888}
yaml

如果配置服务器要求客户端 TLS 证书,你可以通过属性配置客户端 TLS 证书和信任库,如下例所示:

spring:
cloud:
config:
uri: https://myconfig.myconfig.com
tls:
enabled: true
key-store: <path-of-key-store>
key-store-type: PKCS12
key-store-password: <key-store-password>
key-password: <key-password>
trust-store: <path-of-trust-store>
trust-store-type: PKCS12
trust-store-password: <trust-store-password>
yaml

spring.cloud.config.tls.enabled 需要设置为 true 以启用配置客户端的 TLS。当 spring.cloud.config.tls.trust-store 被省略时,将使用 JVM 默认的信任库。spring.cloud.config.tls.key-store-typespring.cloud.config.tls.trust-store-type 的默认值为 PKCS12。当密码属性被省略时,假定为空密码。

如果你使用其他形式的安全措施,可能需要为 ConfigServicePropertySourceLocator 提供一个 RestTemplate(例如,通过在引导上下文中获取并注入它)。

健康指标

Config Client 提供了一个 Spring Boot 健康指示器,它会尝试从 Config Server 加载配置。可以通过设置 health.config.enabled=false 来禁用该健康指示器。出于性能考虑,响应也会被缓存。默认的缓存生存时间为 5 分钟。要更改该值,可以设置 health.config.time-to-live 属性(以毫秒为单位)。

提供自定义的 RestTemplate

在某些情况下,您可能需要自定义客户端向配置服务器发出的请求。通常,这样做涉及传递特殊的 Authorization 头以对服务器的请求进行身份验证。

使用配置数据提供自定义的 RestTemplate

在使用 Config Data 时提供一个自定义的 RestTemplate

  1. 创建一个实现 BootstrapRegistryInitializer 的类

    public class CustomBootstrapRegistryInitializer implements BootstrapRegistryInitializer {

    @Override
    public void initialize(BootstrapRegistry registry) {
    registry.register(RestTemplate.class, context -> {
    RestTemplate restTemplate = new RestTemplate();
    // 在这里自定义 RestTemplate
    return restTemplate;
    });
    }

    }
    java
  2. resources/META-INF 目录下,创建一个名为 spring.factories 的文件,并指定你的自定义配置,如下例所示:

    org.springframework.boot.BootstrapRegistryInitializer=com.my.config.client.CustomBootstrapRegistryInitializer
    properties

使用 Bootstrap 提供自定义 RestTemplate

在使用 Bootstrap 时提供自定义的 RestTemplate

  1. 创建一个新的配置 Bean,并实现 PropertySourceLocator,如下例所示:

    @Configuration
    public class CustomConfigServiceBootstrapConfiguration {
    @Bean
    public ConfigServicePropertySourceLocator configServicePropertySourceLocator() {
    ConfigClientProperties clientProperties = configClientProperties();
    ConfigServicePropertySourceLocator configServicePropertySourceLocator = new ConfigServicePropertySourceLocator(clientProperties);
    configServicePropertySourceLocator.setRestTemplate(customRestTemplate(clientProperties));
    return configServicePropertySourceLocator;
    }
    }
    java
    备注

    为了简化添加 Authorization 请求头的操作,可以使用 spring.cloud.config.headers.* 属性来代替。

  2. resources/META-INF 目录下,创建一个名为 spring.factories 的文件,并指定自定义配置,如下例所示:

    org.springframework.cloud.bootstrap.BootstrapConfiguration = com.my.config.client.CustomConfigServiceBootstrapConfiguration
    properties

保险库

当使用 Vault 作为配置服务器的后端时,客户端需要提供一个令牌,以便服务器可以从 Vault 中检索值。这个令牌可以通过在 bootstrap.yml 中设置 spring.cloud.config.token 来在客户端中提供,如下例所示:

spring:
cloud:
config:
token: YourVaultToken
yaml

Vault 中的嵌套键

Vault 支持在存储在 Vault 的值中嵌套键,如下例所示:

echo -n '{"appA": {"secret": "appAsecret"}, "bar": "baz"}' | vault write secret/myapp -

此命令将一个 JSON 对象写入您的 Vault。要在 Spring 中访问这些值,您可以使用传统的点(.)注解,如下例所示

@Value("${appA.secret}")
String name = "World";
java

前面的代码将把 name 变量的值设置为 appAsecret

AOT 和原生镜像支持

4.0.0 版本起,Spring Cloud Config Client 开始支持 Spring AOT 转换和 GraalVM 原生镜像。

注意

AOT 和原生镜像支持不适用于配置优先引导(使用 spring.config.use-legacy-processing=true)。

注意

原生镜像不支持刷新范围。如果您打算将配置客户端应用程序作为原生镜像运行,请确保将 spring.cloud.refresh.enabled 属性设置为 false

注意

在构建包含 Spring Cloud Config Client 的项目时,必须确保其连接的配置数据源(例如 Spring Cloud Config Server、Consul、Zookeeper、Vault 等)可用。例如,如果您从 Spring Cloud Config Server 检索配置数据,请确保其实例正在运行,并且在 Config Client 设置中指定的端口上可用。这是必要的,因为应用程序上下文在构建时进行了优化,并且需要解析目标环境。

注意

由于在 AOT 和原生模式下,配置会在构建时进行处理,并且上下文会在构建时进行优化,因此任何可能影响 Bean 创建的属性(例如在引导上下文中使用的属性)在构建时和运行时都应设置为相同的值,以避免出现意外行为。

注意

由于配置客户端在从原生镜像启动时会连接到正在运行的数据源(如配置服务器),因此快速启动时间将因网络通信所需的时间而减慢。

附录

可观测性元数据

可观测性 - 指标

下面你可以找到该项目声明的所有指标列表。

环境仓库

围绕 EnvironmentRepository 创建的观察。

指标名称 spring.cloud.config.environment.find(由约定类 org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention 定义)。类型 timer

指标名称 spring.cloud.config.environment.find.active(由约定类 org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention 定义)。类型 long task timer

important

在开始观察后添加的 KeyValues 可能会在 *.active 指标中缺失。

important

Micrometer 内部使用 纳秒 作为基本单位。然而,每个后端决定实际的基本单位。(例如,Prometheus 使用秒)

封闭类的完全限定名称 org.springframework.cloud.config.server.environment.DocumentedConfigObservation

important

所有标签必须以前缀 spring.cloud.config.environment 开头!

表 1. 低基数键

名称描述
spring.cloud.config.environment.application (必填)查询属性的应用程序名称。
spring.cloud.config.environment.class (必填)EnvironmentRepository 的实现。
spring.cloud.config.environment.label (必填)查询属性的标签。
spring.cloud.config.environment.profile (必填)查询属性的应用程序名称。

可观测性 - 跨度

以下您可以找到本项目声明的所有跨度的列表。

环境仓库跨度

围绕 EnvironmentRepository 创建的观察。

Span 名称 spring.cloud.config.environment.find(由约定类 org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention 定义)。

封闭类的完全限定名称 org.springframework.cloud.config.server.environment.DocumentedConfigObservation

important

所有标签必须以 spring.cloud.config.environment 为前缀!

表 2. 标签键

名称描述
spring.cloud.config.environment.application (必填)查询属性所属的应用程序名称。
spring.cloud.config.environment.class (必填)EnvironmentRepository 的实现类。
spring.cloud.config.environment.label (必填)查询属性所属的标签。
spring.cloud.config.environment.profile (必填)查询属性所属的应用程序名称。