Spring Cloud Config 客户端
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:
这将连接到默认位置为 [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 进行安全保护,你可以将凭据配置为 user
和 password
。此外,如果 Config Server 有上下文路径,你可以设置 configPath
。例如,以下 YAML 文件适用于作为 Eureka 客户端的 Config Server:
eureka:
instance:
...
metadataMap:
user: osufhalskjrtl
password: lviuhlszvaorhvlo5847
configPath: /config
使用 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-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
属性仍然会生效。关于它们如何使用的详细信息可以在 Spring Retry 中的 ExponentialRandomBackOffPolicy
和 ExponentialBackOffPolicy
中找到。
要完全控制重试行为并且正在使用传统引导程序,请添加一个类型为 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"
这将设置 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.*
(其中 *
是 name
、profile
或 label
)来覆盖所有这些配置。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
以下示例展示了传递相同信息的另一种方式:
spring:
cloud:
config:
uri: https://myconfig.mycompany.com
username: user
password: secret
spring.cloud.config.password
和 spring.cloud.config.username
的值会覆盖 URI 中提供的任何内容。
如果你在 Cloud Foundry 上部署你的应用程序,提供密码的最佳方式是通过服务凭证(例如在 URI 中,因为它不需要在配置文件中)。以下示例在本地和名为 configserver
的 Cloud Foundry 用户提供的服务上都可以工作:
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。当密码属性被省略时,假定为空密码。
如果你使用其他形式的安全措施,可能需要为 ConfigServicePropertySourceLocator
提供一个 RestTemplate(例如,通过在引导上下文中获取并注入它)。
健康指标
Config Client 提供了一个 Spring Boot 健康指示器,它会尝试从 Config Server 加载配置。可以通过设置 health.config.enabled=false
来禁用该健康指示器。出于性能考虑,响应也会被缓存。默认的缓存生存时间为 5 分钟。要更改该值,可以设置 health.config.time-to-live
属性(以毫秒为单位)。
提供自定义的 RestTemplate
在某些情况下,您可能需要自定义客户端向配置服务器发出的请求。通常,这样做涉及传递特殊的 Authorization
头以对服务器的请求进行身份验证。
使用配置数据提供自定义的 RestTemplate
在使用 Config Data 时提供一个自定义的 RestTemplate
:
-
创建一个实现
BootstrapRegistryInitializer
的类public class CustomBootstrapRegistryInitializer implements BootstrapRegistryInitializer {
@Override
public void initialize(BootstrapRegistry registry) {
registry.register(RestTemplate.class, context -> {
RestTemplate restTemplate = new RestTemplate();
// 在这里自定义 RestTemplate
return restTemplate;
});
}
} -
在
resources/META-INF
目录下,创建一个名为spring.factories
的文件,并指定你的自定义配置,如下例所示:org.springframework.boot.BootstrapRegistryInitializer=com.my.config.client.CustomBootstrapRegistryInitializer
使用 Bootstrap 提供自定义 RestTemplate
在使用 Bootstrap 时提供自定义的 RestTemplate
:
-
创建一个新的配置 Bean,并实现
PropertySourceLocator
,如下例所示:@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
的文件,并指定自定义配置,如下例所示:org.springframework.cloud.bootstrap.BootstrapConfiguration = com.my.config.client.CustomConfigServiceBootstrapConfiguration
保险库
当使用 Vault 作为配置服务器的后端时,客户端需要提供一个令牌,以便服务器可以从 Vault 中检索值。这个令牌可以通过在 bootstrap.yml
中设置 spring.cloud.config.token
来在客户端中提供,如下例所示:
spring:
cloud:
config:
token: YourVaultToken
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 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
。
在开始观察后添加的 KeyValues 可能会在 *.active 指标中缺失。
Micrometer 内部使用 纳秒
作为基本单位。然而,每个后端决定实际的基本单位。(例如,Prometheus 使用秒)
封闭类的完全限定名称 org.springframework.cloud.config.server.environment.DocumentedConfigObservation
。
所有标签必须以前缀 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
。
所有标签必须以 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 (必填) | 查询属性所属的应用程序名称。 |