|
此版本仍在开发中,目前尚不稳定。如需最新稳定版本,请使用 Spring Cloud Config 5.0.1! |
Spring Cloud Config Client
Spring Boot 应用程序可以立即利用 Spring 配置服务器(或由应用程序开发者提供的其他外部属性源)。它还会自动获取一些与 Environment 变更事件相关的额外有用功能。
Spring Boot 配置数据导入
Spring Boot 2.4 引入了一种通过 spring.config.import 属性导入配置数据的新方式。如今,这是绑定到配置服务器的默认方式。
可选地连接到配置服务器,请在 application.properties 中设置以下内容:
spring.config.import=optional:configserver:
这将连接到配置服务器的默认位置“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 Boot 配置数据导入方法时,无需 bootstrap 文件(属性文件或 YAML 文件)即可通过 spring.config.import 进行导入。 |
配置首 Bootstrap
要使用传统的 Bootstrap 方式连接到配置服务器,必须通过属性或 spring-cloud-starter-bootstrap Starters启用 Bootstrap。该属性为 spring.cloud.bootstrap.enabled=true。它必须设置为系统属性或环境变量。
一旦启用了 Bootstrap,任何类路径中包含 Spring Cloud Config Client 的应用程序都将按照如下方式连接到配置服务器:
当配置客户端启动时,它会通过 spring.cloud.config.uri 的 Bootstrap 配置属性绑定到配置服务器,并使用远程属性源初始化 Spring Environment。
这种行为的最终结果是,所有希望使用配置服务器的客户端应用程序都需要在 bootstrap.yml(或环境变量)中设置服务器地址 spring.cloud.config.uri(默认值为 "http://localhost:8888")。
发现首次查找
除非您正在使用 配置优先引导,否则您需要在配置属性中包含一个 spring.config.import 属性,并带有 optional: 前缀。例如,spring.config.import=optional:configserver:。 |
如果您使用 DiscoveryClient 实现方式,例如 Spring Cloud Netflix 和 Eureka 服务发现或 Spring Cloud Consul,您可以使配置服务器注册到发现服务中。
如果您更倾向于使用 DiscoveryClient 来定位配置服务器,可以通过设置 spring.cloud.config.discovery.enabled=true 实现(默认值为 false)。
例如,在 Spring Cloud Netflix 中,您需要定义 Eureka 服务器地址(例如,在 eureka.client.serviceUrl.defaultZone 中进行配置)。
使用此选项的代价是在启动时多一次网络往返,用于定位服务注册信息。
其优势在于:只要发现服务(Discovery Service)是固定点,配置服务器就可以更改其位置坐标。
默认服务 ID 是 configserver,但您可以在客户端通过设置 spring.cloud.config.discovery.serviceId 进行修改(在服务端,则可通过常规的服务配置方式,如设置 spring.application.name 来实现)。
发现客户端实现均支持某种元数据映射(例如,我们有 eureka.instance.metadataMap 用于 Eureka)。
一些额外的配置服务器属性可能需要在服务注册元数据中进行配置,以便客户端能够正确连接。
如果配置服务器使用 HTTP 基本认证进行保护,您可以将凭据配置为 user 和 password。
此外,如果配置服务器具有上下文路径,您可以设置 configPath。
例如,以下 YAML 文件是用于一个作为 Eureka 客户端的配置服务器:
eureka:
instance:
...
metadataMap:
user: osufhalskjrtl
password: lviuhlszvaorhvlo5847
configPath: /config
配置客户端快速失败
在某些情况下,您可能希望如果服务无法连接到配置服务器,则中止服务的启动。如果这是所需的行为,请将引导配置属性 spring.cloud.config.fail-fast=true 设置为使客户端抛出异常并停止运行。
要使用 spring.config.import 实现类似的功能,只需省略 optional: 前缀即可。 |
配置客户端重试
如果您预期配置服务器在应用程序启动时可能偶尔不可用,您可以使其在失败后继续重试。
首先,您需要设置 spring.cloud.config.fail-fast=true。
然后,您需要将 spring-retry 和 spring-boot-starter-aop 添加到您的类路径中。
默认行为是在初始退避间隔为 1000 毫秒、后续退避的指数乘数为 1.1 的情况下重试六次。
您可以通过设置 spring.cloud.config.retry.* 配置属性来配置这些属性(以及其他属性)。
要使用随机指数退避策略,请将 spring.cloud.config.retry.useRandomPolicy 设置为 true。
当 spring.cloud.config.retry.useRandomPolicy 为 true 时,max-attempts、initial-interval、max-interval 和 multiplier 属性即使在使用随机指数退避策略时仍会产生影响。其具体使用方式可参见 ExponentialRandomBackOffPolicy 和 ExponentialBackOffPolicy 在 Spring Retry 中的相关说明。 |
要完全控制重试行为且正在使用传统的引导(bootstrap)方式,请添加一个类型为 RetryOperationsInterceptor、ID 为 configServerRetryInterceptor 的 @Bean。Spring Retry 提供了一个 RetryInterceptorBuilder,支持创建一个。 |
配置客户端重试与 spring.config.import
重试功能与 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"
这会设置 spring.cloud.config.fail-fast=true(注意上方缺少前缀),并配置所有可用的 spring.cloud.config.retry.* 属性。
定位远程配置资源
配置服务从 /{application}/{profile}/{label} 提供属性源,其中客户端应用的默认绑定如下:
-
"application" =
${spring.application.name} -
"profile" =
${spring.profiles.active}(实际为Environment.getActiveProfiles()) -
<label> = "master"
当设置属性 ${spring.application.name} 时,请勿在应用名称前添加保留字 application-,以避免解析正确的属性源时出现问题。 |
您可以通过设置 spring.cloud.config.* 来重写所有这些选项(其中 * 是 name、profile 或 label)。label 对于回滚到先前的配置版本非常有用。在默认的配置服务器实现中,它可以是一个 Git 标签、分支名称或提交 ID。标签也可以以逗号分隔的列表形式提供。当您在功能分支上工作时,这种行为会很有用。例如,您可能希望将配置标签与您的分支对齐,但使其成为可选的(此时,请使用 spring.cloud.config.label=myfeature,develop)。
请求多个标签
在 Spring Cloud Config 4.2.0 之前,如果将 spring.cloud.config.label 设置为用逗号分隔的标签列表,Config 客户端会依次尝试每个标签,通过向 Config Server 发送请求来查找首个可用的标签。这意味着,一旦找到第一个标签,后续的标签将不再被尝试。
截至 Spring Cloud Config 4.2.0,如果您将 spring.cloud.config.label 设置为用逗号分隔的标签列表 且 将 spring.cloud.config.send-all-labels 设置为该值,配置客户端将向配置服务器发出单次请求,并附带该逗号分隔的标签列表;如果 配置服务器使用的是 4.2.0 版本或更高版本,它将返回一个单一响应,其中包含所有标签对应的属性源。
将 spring.cloud-config.send-all-labels 设置为 true,将 spring.cloud.config.label 设置为以逗号分隔的标签列表,并使用低于 4.2.0 版本的配置服务器(Config Server),将导致意外行为,因为配置服务器会尝试查找与逗号分隔列表值相匹配的标签,而不会尝试将标签拆分处理。 |
通过在单个请求中发送所有标签,可以减少对配置服务器的请求数量。
spring.cloud.config.send-all-labels 默认设置为 false,因此旧行为仍然是默认值,并且还保持了与 Config Server 旧版本的兼容性。
为配置服务器指定多个URL
为确保高可用性,当您部署了多个 Config Server 实例,并期望其中一或多个实例偶尔不可用或无法响应请求(例如 Git 服务器宕机时),您可以选择以下任一方式:在 spring.cloud.config.uri 属性下以逗号分隔的列表形式指定多个 URL,或让所有实例在服务注册中心(如 Eureka)中注册(若使用 Discovery-First 启动模式)。
在spring.cloud.config.uri下列出的URL将按列出的顺序依次尝试。默认情况下,配置客户端会尝试从每个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 基本认证,则客户端需要知道密码(如果用户名不是默认值,还需知道用户名)。<br/>您可以通过配置服务器的 URI 或通过独立的用户名和密码属性来指定用户名和密码,如下例所示:
spring:
cloud:
config:
uri: https://user:[email protected]
以下示例展示了另一种传递相同信息的方式:
spring:
cloud:
config:
uri: https://myconfig.mycompany.com
username: user
password: secret
The spring.cloud.config.password and spring.cloud.config.username values override anything that is provided in the URI.
如果您在 Cloud Foundry 上部署应用,则提供密码的最佳方式是通过服务凭据(例如在 URI 中,因为无需将其放在配置文件中)。
以下示例在本地以及在 Cloud Foundry 上名为 configserver 的用户提供的服务上均能正常工作。
spring:
cloud:
config:
uri: ${vcap.services.configserver.credentials.uri:http://user:password@localhost:8888}
如果配置服务器需要客户端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>
需要将 spring.cloud.config.tls.enabled 设置为 true 以启用配置客户端的 TLS。当 spring.cloud.config.tls.trust-store 被省略时,将使用 JVM 的默认信任库。默认情况下,spring.cloud.config.tls.key-store-type 和 spring.cloud.config.tls.trust-store-type 的值为 PKCS12。当密码属性被省略时,默认假设为空密码。
如果您使用其他形式的安全机制,可能需要 为 RestTemplate 提供一个 ConfigServicePropertySourceLocator(例如,通过在引导上下文中获取它并注入)。
健康指标
配置客户端提供了一个 Spring Boot 健康指标,该指标尝试从配置服务器加载配置。
可以通过设置 management.health.config.enabled=false 来禁用该健康指标。
出于性能考虑,响应也会被缓存。
默认的缓存生存时间(TTL)为 5 分钟。
若要更改此值,请设置 health.config.time-to-live 属性(单位:毫秒)。
提供自定义 RestTemplate
在某些情况下,您可能需要自定义客户端向配置服务器发出的请求。
通常,这样做的方法是传递特殊的 Authorization 头部以对服务器请求进行身份验证。
使用配置数据提供自定义 RestTemplate
当使用配置数据时,提供自定义 RestTemplate:
-
创建一个实现
BootstrapRegistryInitializer的类CustomBootstrapRegistryInitializer.javapublic class CustomBootstrapRegistryInitializer implements BootstrapRegistryInitializer { @Override public void initialize(BootstrapRegistry registry) { registry.register(RestTemplate.class, context -> { RestTemplate restTemplate = new RestTemplate(); // Customize RestTemplate here return restTemplate; }); } } -
在
resources/META-INF中,创建一个名为spring.factories的文件,并指定您的自定义配置,如下所示示例:spring.factoriesorg.springframework.boot.BootstrapRegistryInitializer=com.my.config.client.CustomBootstrapRegistryInitializer
使用 Bootstrap 提供自定义 RestTemplate
为使用 Bootstrap 提供自定义 RestTemplate:
-
创建一个新的配置bean,其包含
PropertySourceLocator的实现,如以下示例所示:CustomConfigServiceBootstrapConfiguration.java@Configuration public class CustomConfigServiceBootstrapConfiguration { @Bean public ConfigServicePropertySourceLocator configServicePropertySourceLocator() { ConfigClientProperties clientProperties = configClientProperties(); ConfigServicePropertySourceLocator configServicePropertySourceLocator = new ConfigServicePropertySourceLocator(clientProperties); configServicePropertySourceLocator.setRestTemplate(customRestTemplate(clientProperties)); return configServicePropertySourceLocator; } }对于简化添加 Authorization头部的方法,可以使用spring.cloud.config.headers.*属性来替代。 -
在
resources/META-INF中,创建一个名为spring.factories的文件,并指定您的自定义配置,如下所示示例:spring.factoriesorg.springframework.cloud.bootstrap.BootstrapConfiguration = com.my.config.client.CustomConfigServiceBootstrapConfiguration
Vault 中的嵌套密钥
Vault 支持在 Vault 中存储的值内嵌套键,如下例所示:
echo -n '{"appA": {"secret": "appAsecret"}, "bar": "baz"}' | vault write secret/myapp -
此命令将 JSON 对象写入您的 Vault。要是在 Spring 中访问这些值,您可使用传统的点(.)注解,如下例所示。
@Value("${appA.secret}")
String name = "World";
前面的代码会将变量 name 的值设置为 appAsecret。
AOT 和原生映像支持
自 4.0.0 版本起,Spring Cloud Config 客户端支持 Spring AOT 转换和 GraalVM 原生镜像。
原生镜像支持(AOT 和 native image support)不适用于 配置优先启动(使用 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。
| 在启动 Observation 后添加的 KeyValues 可能会缺失于 *.active 指标中。 |
Micrometer 内部使用 nanoseconds 作为基本单位。然而,每个后端决定实际的基本单位。(即 Prometheus 使用秒) |
封闭类 org.springframework.cloud.config.server.environment.DocumentedConfigObservation 的全限定名。
所有标签都必须以 spring.cloud.config.environment 前缀开头! |
姓名 |
描述 |
|
用于查询属性的应用程序名称。 |
|
EnvironmentRepository 的实现。 |
|
用于查询哪些属性的标签。 |
|
用于查询属性的应用程序名称。 |
可观测性 - 跨度
以下列出了本项目声明的所有 span。
环境存储库跨度
围绕 EnvironmentRepository 创建了观察。
Span 名称 spring.cloud.config.environment.find(由约定类 org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention 定义)。
封闭类 org.springframework.cloud.config.server.environment.DocumentedConfigObservation 的全限定名。
所有标签都必须以 spring.cloud.config.environment 前缀开头! |
姓名 |
描述 |
|
用于查询属性的应用程序名称。 |
|
EnvironmentRepository 的实现。 |
|
用于查询哪些属性的标签。 |
|
用于查询属性的应用程序名称。 |