# Spring Cloud 配置

**3.1.1**

Spring Cloud 配置为分布式系统中的外部化配置提供服务器端和客户端支持。有了 Config 服务器，你就有了一个中心位置来管理跨所有环境的应用程序的外部属性。客户机和服务器上的概念都映射到 Spring `Environment`和`PropertySource`的抽象，因此它们非常适合 Spring 应用程序，但可以用于运行在任何语言中的任何应用程序。当应用程序通过部署管道从开发到测试再到生产时，你可以管理这些环境之间的配置，并确保应用程序在迁移时拥有运行它们所需的一切。服务器存储后端的默认实现使用 Git，因此它很容易支持配置环境的标记版本，并且可以访问用于管理内容的各种工具。添加替代实现并将其插入 Spring 配置中是很容易的。

## [快速启动](#_quick_start)

这个快速启动同时使用了 Spring Cloud Config 服务器的服务器和客户端。

首先，启动服务器，如下所示：

```
$ cd spring-cloud-config-server
$ ../mvnw spring-boot:run
```

服务器是一个 Spring 引导应用程序，因此如果你愿意，可以从 IDE 运行它（主类是`ConfigServerApplication`）。

下一步测试一个客户机，如下所示：

```
$ curl localhost:8888/foo/development
{
  "name": "foo",
  "profiles": [
    "development"
  ]
  ....
  "propertySources": [
    {
      "name": "https://github.com/spring-cloud-samples/config-repo/foo-development.properties",
      "source": {
        "bar": "spam",
        "foo": "from foo development"
      }
    },
    {
      "name": "https://github.com/spring-cloud-samples/config-repo/foo.properties",
      "source": {
        "foo": "from foo props",
        "democonfigclient.message": "hello spring io"
      }
    },
    ....
```

定位属性源的默认策略是克隆一个 Git 存储库（at`spring.cloud.config.server.git.uri`），并使用它初始化一个 mini`SpringApplication`。迷你应用程序的`Environment`用于枚举属性源并在 JSON 端点上发布它们。

HTTP 服务具有以下形式的资源：

```
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
```

例如：

```
curl localhost:8888/foo/development
curl localhost:8888/foo/development/master
curl localhost:8888/foo/development,db/master
curl localhost:8888/foo-development.yml
curl localhost:8888/foo-db.properties
curl localhost:8888/master/foo-db.properties
```

其中`application`在`SpringApplication`中被注入为`spring.config.name`（在常规 Spring 引导应用程序中通常`application`），`profile`是一个活动配置文件（或逗号分隔的属性列表），而`label`是一个可选的 git 标签（默认为`master`）。

Spring Cloud 配置服务器从各种来源获取远程客户端的配置。下面的示例从 Git 存储库（必须提供）获取配置，如下面的示例所示：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
```

其他来源包括任何与 JDBC 兼容的数据库、Subversion、HashiCorpVault、Credhub 和本地文件系统。

### [客户端使用](#_client_side_usage)

要在应用程序中使用这些特性，你可以将其构建为一个依赖于 Spring-cloud-config-client 的 Spring 引导应用程序（例如，请参见 config-client 或示例应用程序的测试用例）。添加依赖项最方便的方法是使用 Spring 引导启动器`org.springframework.cloud:spring-cloud-starter-config`。还有一个用于 Maven 用户的父 POM 和 BOM（），以及用于 Gradle 和 Spring CLI 用户的 Spring IO 版本管理属性文件。下面的示例显示了典型的 Maven 配置：

POM.xml

```
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>{spring-boot-docs-version}</version>
       <relativePath /> <!-- lookup parent from repository -->
   </parent>

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>{spring-cloud-version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-config</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

<build>
	<plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
	</plugins>
</build>

   <!-- repositories also needed for snapshots and milestones -->
```

现在，你可以创建一个标准的 Spring 启动应用程序，例如下面的 HTTP 服务器：

```
@SpringBootApplication
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello World!";
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
```

当此 HTTP 服务器运行时，它会从端口 8888 上的默认本地配置服务器（如果正在运行）获取外部配置。要修改启动行为，可以使用`应用程序.属性`更改配置服务器的位置，如下例所示：

```
spring.config.import=optional:configserver:http://myconfigserver.com
```

默认情况下，如果没有设置应用程序名称，将使用`application`。要修改名称，可以将以下属性添加到`应用程序.属性`文件中：

```
spring.application.name: myapp
```

|   |在设置属性`${spring.application.name}`时，不要在应用程序名称前加上保留的单词`application-`，以防止解决正确属性源的问题。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

配置服务器属性在`/env`端点中显示为高优先级属性源，如下面的示例所示。

```
$ curl localhost:8080/env
{
  "activeProfiles": [],
  {
    "name": "servletContextInitParams",
    "properties": {}
  },
  {
    "name": "configserver:https://github.com/spring-cloud-samples/config-repo/foo.properties",
    "properties": {
      "foo": {
        "value": "bar",
        "origin": "Config Server https://github.com/spring-cloud-samples/config-repo/foo.properties:2:12"
      }
    }
  },
  ...
}
```

一个名为`configserver:<URL of remote repository>/<file name>`的属性源包含`foo`属性，其值为`bar`。

|   |属性源名称中的 URL 是 Git 存储库，而不是 Config Server URL。|
|---|-------------------------------------------------------------------------------------|

|   |如果使用 Spring Cloud Config Client，则需要设置`spring.config.import`属性才能绑定到 Config Server。你可以阅读有关它的更多信息[in the Spring Cloud Config Reference Guide](https://docs.spring.io/spring-cloud-config/docs/current/reference/html/#config-data-import)。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## [Spring Cloud Config Server](#_spring_cloud_config_server)

Spring Cloud 配置服务器提供了用于外部配置（名称-值对或等效的 YAML 内容）的基于 HTTP 资源的 API。通过使用`@EnableConfigServer`注释，服务器可嵌入到 Spring 引导应用程序中。因此，以下应用程序是一个配置服务器：

configserver.java

```
@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
  public static void main(String[] args) {
    SpringApplication.run(ConfigServer.class, args);
  }
}
```

像所有 Spring 启动应用程序一样，它默认情况下在 8080 端口上运行，但你可以通过各种方式将其切换到更传统的 8888 端口。最简单的方法是用`spring.config.name=configserver`启动它（在配置服务器 jar 中有一个`configserver.yml`）。另一种方法是使用自己的`应用程序.属性`，如下例所示：

application.properties

```
server.port: 8888
spring.cloud.config.server.git.uri: file://${user.home}/config-repo
```

其中`${user.home}/config-repo`是一个包含 YAML 和 Properties 文件的 Git 存储库。

|   |在 Windows 上，如果文件 URL 是绝对的，并带有驱动器前缀（例如，`[file:///${user.home}/config-repo](file:///${user.home}/config-repo)`），则需要在文件 URL 中添加一个额外的“/”。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |下面的清单显示了在前面的示例中创建 Git 存储库的方法：<br/><br/>```<br/>$ cd $HOME<br/>$ mkdir config-repo<br/>$ cd config-repo<br/>$ git init .<br/>$ echo info.foo: bar > application.properties<br/>$ git add -A .<br/>$ git commit -m "Add application.properties"<br/>```|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |为你的 Git 存储库使用本地文件系统仅用于测试。<br/>你应该在生产中使用服务器来托管你的配置存储库。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |如果只保存文本文件，那么配置存储库的初始克隆将是快速有效的。<br/>如果存储二进制文件，特别是大的二进制文件，你可能会在第一次请求配置时遇到延迟，或者在服务器中遇到内存不足的错误。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### [环境存储库](#_environment_repository)

你应该将配置服务器的配置数据存储在哪里？管理这种行为的策略是`EnvironmentRepository`，它服务于`Environment`对象。这`Environment`是从 Spring `Environment`的域的浅拷贝（包括以`propertySources`为主要特征）。`Environment`资源由三个变量参数化：

* `{application}`，它映射到客户端的`spring.application.name`。

* `{profile}`，它映射到客户机上的`spring.profiles.active`（以逗号分隔的列表）。

* `{label}`，这是一个服务器端特性，标记了一组“版本控制的”配置文件。

存储库实现的行为通常类似于 Spring 引导应用程序，从一个`spring.config.name`等于`{application}`参数和`spring.profiles.active`等于`{profiles}`参数加载配置文件。配置文件的优先规则也与常规 Spring 引导应用程序中的规则相同：活动配置文件优先于默认值，并且，如果有多个配置文件，则最后一个优先（类似于将条目添加到`Map`）。

以下示例客户机应用程序具有此引导程序配置：

```
spring:
  application:
    name: foo
  profiles:
    active: dev,mysql
```

（与 Spring 引导应用程序的通常情况一样，这些属性也可以通过环境变量或命令行参数来设置）。

如果存储库是基于文件的，那么服务器将从`应用程序.yml`（所有客户机之间共享）和`foo.yml`（以`foo.yml`优先）创建`Environment`。如果 YAML 文件中有指向 Spring 配置文件的文档，则应用这些文档的优先级更高（按所列配置文件的顺序排列）。如果存在特定于配置文件的 YAML（或 Properties）文件，那么这些文件的应用优先级也要高于默认值。更高的优先级表示在`Environment`中列出的`PropertySource`。（这些相同的规则也适用于独立的启动应用程序。

你可以将 Spring.cloud.config.server.accept-empty 设置为 false，这样，如果没有找到应用程序，服务器将返回 HTTP404 状态。默认情况下，此标志设置为 true。

#### [Git 后端](#_git_backend)

`EnvironmentRepository`的默认实现使用了 Git 后端，这对于管理升级和物理环境以及审核更改非常方便。要更改存储库的位置，可以在配置服务器中设置`spring.cloud.config.server.git.uri`配置属性（例如在`application.yml`中）。如果你使用`file:`前缀设置它，那么它应该在本地存储库中工作，这样你就可以在没有服务器的情况下快速轻松地启动它。然而，在这种情况下，服务器直接在本地存储库上操作，而不克隆它（如果它不是裸露的，那也没关系，因为配置服务器从不对“远程”存储库进行更改）。要扩展配置服务器并使其高度可用，你需要让服务器的所有实例指向同一个存储库，这样只有共享文件系统才能工作。即使在这种情况下，对于共享文件系统存储库也最好使用`ssh:`协议，这样服务器就可以克隆它并使用本地工作副本作为缓存。

这个存储库实现将 HTTP 资源的`{label}`参数映射到一个 Git 标签（提交 ID、分支名称或标记）。如果 Git 分支或标记名包含斜杠（`/`），那么 HTTP URL 中的标签应该使用特殊字符串`(_)`来指定（以避免与其他 URL 路径产生歧义）。例如，如果标签是`foo/bar`，替换斜杠将导致以下标签：`foo(_)bar`。特殊字符串`(_)`的包含也可以应用于`{application}`参数。如果你使用命令行客户机（如 curl），请小心 URL 中的括号——你应该用单引号（“”）将它们从 shell 中转出。

##### [跳过 SSL 证书验证](#_skipping_ssl_certificate_validation)

通过将`git.SkipsslValidation`属性设置为`true`（默认设置为`false`），可以禁用配置服务器对 Git 服务器的 SSL 证书的验证。

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          skipSslValidation: true
```

##### [设置 HTTP 连接超时](#_setting_http_connection_timeout)

你可以配置配置服务器等待获得 HTTP 连接的时间（以秒为单位）。使用`git.timeout`属性。

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          timeout: 4
```

##### [git uri 中的占位符](#_placeholders_in_git_uri)

Spring Cloud Config Server 支持带有`{application}`和`{profile}`占位符的 Git Repository URL（如果需要的话，还支持`{label}`，但请记住该标签无论如何都是作为 Git 标签应用的）。因此，你可以使用类似于以下结构的结构来支持“每个应用程序一个存储库”策略：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/myorg/{application}
```

你还可以使用类似的模式，但使用`{profile}`，支持“每个配置文件一个存储库”策略。

此外，使用`{application}`参数中的特殊字符串“（\_）”可以启用对多个组织的支持，如以下示例所示：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/{application}
```

其中`{application}`在请求时以以下格式提供：`organization(_)application`。

##### [模式匹配和多个存储库](#_pattern_matching_and_multiple_repositories)

Spring Cloud 配置还包括支持在应用程序和配置文件名称上与模式匹配的更复杂的需求。模式格式是用逗号分隔的带有通配符的`{application}/{profile}`名称列表（请注意，以通配符开头的模式可能需要引用），如下例所示：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          repos:
            simple: https://github.com/simple/config-repo
            special:
              pattern: special*/dev*,*special*/dev*
              uri: https://github.com/special/config-repo
            local:
              pattern: local*
              uri: file:/home/configsvc/config-repo
```

如果`{application}/{profile}`不匹配任何模式，则使用在`spring.cloud.config.server.git.uri`下定义的默认 URI。在上面的示例中，对于“简单”存储库，模式是`simple/*`（在所有配置文件中，它只匹配一个名为`simple`的应用程序）。“local”存储库匹配所有配置文件中以`local`开头的所有应用程序名称（`/*`后缀会自动添加到任何没有配置文件匹配器的模式中）。

|   |“简单”示例中使用的“单行”捷径仅在要设置的唯一属性是 URI 时才能使用。<br/>如果需要设置其他任何内容（凭据、模式等），则需要使用完整的表单。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

repo 中的`pattern`属性实际上是一个数组，因此可以使用 YAML 数组（或`[0]`、`[1]`等属性文件中的后缀）绑定到多个模式。如果要运行带有多个配置文件的应用程序，你可能需要这样做，如以下示例所示：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          repos:
            development:
              pattern:
                - '*/development'
                - '*/staging'
              uri: https://github.com/development/config-repo
            staging:
              pattern:
                - '*/qa'
                - '*/production'
              uri: https://github.com/staging/config-repo
```

|   |Spring Cloud 猜测，包含配置文件的模式不以`*`结束，这意味着你实际上希望匹配以该模式开始的配置文件列表（因此`*/staging`是`["*/staging", "*/staging,*"]`的快捷方式，以此类推）。<br/>例如，这是常见的，你需要在本地运行“开发”配置文件中的应用程序，还需要远程运行“云”配置文件中的应用程序。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

每个存储库还可以选择将配置文件存储在子目录中，搜索这些目录的模式可以指定为`search-paths`。下面的示例显示了顶层的配置文件：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          search-paths:
            - foo
            - bar*
```

在前面的示例中，服务器在顶层和`foo/`子目录以及名称以`bar`开头的任意子目录中搜索配置文件。

默认情况下，服务器在首次请求配置时复制远程存储库。可以将服务器配置为在启动时克隆存储库，如下面的顶级示例所示：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://git/common/config-repo.git
          repos:
            team-a:
                pattern: team-a-*
                cloneOnStart: true
                uri: https://git/team-a/config-repo.git
            team-b:
                pattern: team-b-*
                cloneOnStart: false
                uri: https://git/team-b/config-repo.git
            team-c:
                pattern: team-c-*
                uri: https://git/team-a/config-repo.git
```

在前面的示例中，服务器在接受任何请求之前，在启动时复制 Team-A 的 config-repo。在请求从存储库进行配置之前，不会克隆所有其他存储库。

|   |在配置服务器启动时，设置要在配置服务器启动时克隆的存储库，可以帮助快速识别配置错误的配置源（例如无效的存储库 URI），<br/>with`cloneOnStart`配置源未启用，配置服务器可以使用配置错误或无效的配置源成功启动，并且在应用程序从该配置源请求配置之前不会检测到错误。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### [认证](#_authentication)

要在远程存储库上使用 HTTP Basic 身份验证，请分别添加`username`和`password`属性（不在 URL 中），如以下示例所示：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          username: trolley
          password: strongpassword
```

如果你不使用 HTTPS 和用户凭据，那么当你将密钥存储在默认目录（`~/.ssh`）中并且 URI 指向 SSH 位置（例如`[[email protected]](/cdn-cgi/l/email-protection):configuration/cloud-configuration`）时，SSH 也应该可以开箱即用。在`~/.ssh/known_hosts`文件中存在用于 Git 服务器的条目，并且该条目是`ssh-rsa`格式，这一点很重要。不支持其他格式（如`ecdsa-sha2-nistp256`）。为了避免意外，你应该确保 Git 服务器的`known_hosts`文件中只有一个条目，并且它与你提供给 Config 服务器的 URL 相匹配。如果在 URL 中使用主机名，则希望在`known_hosts`文件中使用该主机名（而不是 IP）。通过使用 JGIT 访问存储库，因此你在其中找到的任何文档都应该适用。HTTPS 代理设置可以设置在`~/.git/config`中，或者（以与任何其他 JVM 进程相同的方式）使用系统属性（`-Dhttps.proxyHost`和`-Dhttps.proxyPort`）。

|   |如果你不知道你的`~/.git`目录在哪里，请使用`git config --global`来操作设置（例如，`git config --global http.sslVerify false`）。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|

JGIT 需要 PEM 格式的 RSA 密钥。下面是一个示例 ssh-keygen（来自 OpenSSH）命令，它将以 CORECT 格式生成一个键：

```
ssh-keygen -m PEM -t rsa -b 4096 -f ~/config_server_deploy_key.rsa
```

警告：在使用 SSH 密钥时，预期的 SSH 私钥必须以``-----BEGIN RSA PRIVATE KEY-----``开头。如果密钥以``-----BEGIN OPENSSH PRIVATE KEY-----``开始，那么当 Spring-cloud-config 服务器启动时，RSA 密钥将不会加载。这个错误看起来是这样的：

```
- Error in object 'spring.cloud.config.server.git': codes [PrivateKeyIsValid.spring.cloud.config.server.git,PrivateKeyIsValid]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [spring.cloud.config.server.git.,]; arguments []; default message []]; default message [Property 'spring.cloud.config.server.git.privateKey' is not a valid private key]
```

要纠正上述错误，必须将 RSA 键转换为 PEM 格式。上面提供了一个使用 OpenSSH 生成适当格式的新键的示例。

##### [使用 AWS codecommit 进行身份验证](#_authentication_with_aws_codecommit)

Spring Cloud 配置服务器还支持[AWS Codecommit](https://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html)身份验证。当从命令行使用 Git 时，AWS Codecommit 使用身份验证助手。此助手不与 JGIT 库一起使用，因此，如果 Git URI 与 AWS Codecommit 模式匹配，那么将创建用于 AWS Codecommit 的 JGit CredentialProvider。AWS codecommit URI 遵循以下模式：

```
https//git-codecommit.${AWS_REGION}.amazonaws.com/v1/repos/${repo}.
```

如果你提供了带有 AWS CodeCommit URI 的用户名和密码，那么它们必须是提供对存储库访问的[AWS AccessKeyID 和 SecretAccessKey](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSGettingStartedGuide/AWSCredentials.html)。如果你没有指定用户名和密码，那么将使用[AWS 默认凭据提供商链](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html)检索 AccessKeyID 和 SecretAccessKey。

如果你的 Git URI 与 codecommit URI 模式匹配（如前所述），则必须在用户名和密码中或在默认凭据提供商链支持的位置之一中提供有效的 AWS 凭据。AWS EC2 实例可以使用[EC2 实例的 IAM 角色](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)。

|   |`aws-java-sdk-core` jar 是一个可选的依赖项。<br/>如果`aws-java-sdk-core` jar 不在你的 Classpath 上，则不会创建 AWS 代码提交凭据提供程序，而不管 Git 服务器的 URI 是什么。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### [使用 Google Cloud Source 进行身份验证](#_authentication_with_google_cloud_source)

Spring Cloud 配置服务器还支持针对[Google Cloud Source](https://cloud.google.com/source-repositories/)存储库进行身份验证。

如果你的 Git URI 使用`http`或`https`协议，并且域名是`source.developers.google.com`，则将使用 Google Cloud Source 凭据提供商。Google Cloud Source Repository 的 URI 格式为`[https://source.developers.google.com/p/${GCP_PROJECT}/r/${REPO}](https://source.developers.google.com/p/${GCP_PROJECT}/r/${REPO})`。要获得存储库的 URI，请单击 Google Cloud Source UI 中的“Clone”，并选择“手动生成的凭据”。不生成任何凭据，只需复制显示的 URI。

Google Cloud Source 凭据提供商将使用 Google Cloud Platform 应用程序的默认凭据。关于如何为系统创建应用程序默认凭据，请参见[Google Cloud SDK 文档](https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login)。这种方法适用于开发环境中的用户帐户和生产环境中的服务帐户。

|   |`com.google.auth:google-auth-library-oauth2-http`是一个可选的依赖项。<br/>如果`google-auth-library-oauth2-http` jar 不在你的 Classpath 上，则不会创建 Google Cloud Source 凭据提供者，无论 Git 服务器的 URI 是什么。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### [使用属性的 Git SSH 配置](#_git_ssh_configuration_using_properties)

默认情况下， Spring Cloud Config Server 使用的 JGit 库在使用 SSH URI 连接到 Git 存储库时使用诸如`~/.ssh/known_hosts`和`/etc/ssh/ssh_config`等 SSH 配置文件。在云环境中，例如 Cloud Foundry，本地文件系统可能是短暂的，或者不容易访问。对于这些情况，可以使用 Java 属性设置 SSH 配置。为了激活基于属性的 SSH 配置，`spring.cloud.config.server.git.ignoreLocalSshSettings`属性必须设置为`true`，如以下示例所示：

```
  spring:
    cloud:
      config:
        server:
          git:
            uri: [email protected]:team/repo1.git
            ignoreLocalSshSettings: true
            hostKey: someHostKey
            hostKeyAlgorithm: ssh-rsa
            privateKey: |
                         -----BEGIN RSA PRIVATE KEY-----
                         MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
                         IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
                         ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
                         1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
                         oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
                         DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
                         fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
                         BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
                         EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
                         5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
                         +AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
                         pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
                         ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
                         xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
                         dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
                         PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
                         VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
                         FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
                         gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
                         VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
                         cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
                         KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
                         CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
                         q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
                         69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
                         -----END RSA PRIVATE KEY-----
```

下表描述了 SSH 配置属性。

|       Property Name        |备注|
|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **ignoreLocalSshSettings** |如果`true`，使用基于属性而不是基于文件的 SSH 配置。必须在存储库定义中设置为`spring.cloud.config.server.git.ignoreLocalSshSettings`，**不是**。|
|       **privateKey**       |有效的 SSH 私钥。如果`ignoreLocalSshSettings`为 true 且 git uri 为 ssh 格式，则必须设置。|
|        **hostKey**         |有效的 SSH 主机键。如果`hostKeyAlgorithm`也已设置，则必须设置。|
|    **hostKeyAlgorithm**    |`ssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, or ecdsa-sha2-nistp521`中的一个。如果`hostKey`也已设置，则必须设置。|
| **strictHostKeyChecking**  |`true`或`false`。如果为假，请忽略使用主机键的错误。|
|     **knownHostsFile**     |自定义`.known_hosts`文件的位置。|
|**preferredAuthentications**|重写服务器身份验证方法命令.如果服务器在`publickey`方法之前具有键盘交互身份验证，那么这将允许规避登录提示。|

##### [git 搜索路径中的占位符](#_placeholders_in_git_search_paths)

Spring Cloud Config Server 还支持带有`{application}`和`{profile}`（如果需要的话，还支持`{label}`）占位符的搜索路径，如以下示例所示：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          search-paths: '{application}'
```

前面的列表导致在存储库中搜索与目录（以及顶层）同名的文件。通配符在带有占位符的搜索路径中也是有效的（搜索中包含任何匹配的目录）。

##### [强制拉入 Git 存储库](#_force_pull_in_git_repositories)

正如前面提到的， Spring Cloud Config 服务器复制远程 Git 存储库，以防本地副本变脏（例如，由 OS 进程更改的文件夹内容），使得 Spring Cloud Config 服务器无法从远程存储库更新本地副本。

为了解决这个问题，有一个`force-pull`属性，如果本地副本是脏的，该属性将使 Spring Cloud Config 服务器强制从远程存储库中拉出，如以下示例所示：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          force-pull: true
```

如果具有多存储库配置，则可以为每个存储库配置`force-pull`属性，如以下示例所示：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://git/common/config-repo.git
          force-pull: true
          repos:
            team-a:
                pattern: team-a-*
                uri: https://git/team-a/config-repo.git
                force-pull: true
            team-b:
                pattern: team-b-*
                uri: https://git/team-b/config-repo.git
                force-pull: true
            team-c:
                pattern: team-c-*
                uri: https://git/team-a/config-repo.git
```

|   |`force-pull`属性的默认值是`false`。|
|---|-------------------------------------------------------|

##### [删除 Git 存储库中未跟踪的分支](#_deleting_untracked_branches_in_git_repositories)

Spring Cloud Config Server 在检查分支到本地 repo（例如通过标签获取属性）之后具有远程 Git 存储库的克隆，因此它将永远保留该分支，或者直到下一个服务器重新启动（这将创建新的本地 repo）。因此，可能存在这样一种情况，即远程分支被删除，但其本地副本仍可用于获取。而如果 Spring Cloud Config Server Client Service 以`--spring.cloud.config.label=deletedRemoteBranch,master`开始，它将从`deletedRemoteBranch`本地分支获取属性，而不是从`master`获取属性。

为了保持本地存储库分支的清理和到 Remote-`deleteUntrackedBranches`属性可以被设置。它将使 Spring Cloud 配置服务器**力**从本地存储库中删除未跟踪的分支。示例：

```
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          deleteUntrackedBranches: true
```

|   |`deleteUntrackedBranches`属性的默认值是`false`。|
|---|--------------------------------------------------------------------|

##### [Git 刷新率](#_git_refresh_rate)

你可以通过使用`spring.cloud.config.server.git.refreshRate`来控制配置服务器多久会从你的 Git 后端获取更新的配置数据。此属性的值以秒为单位指定。默认情况下，该值为 0，这意味着配置服务器将在每次请求时从 Git Repo 获取更新的配置。

##### [默认标签](#_default_label)

Git 使用的默认标签是`main`。如果没有设置`spring.cloud.config.server.git.defaultLabel`并且一个名为`main`的分支不存在，则默认情况下，配置服务器还将尝试检出一个名为`master`的分支。如果你想禁用回退分支行为，那么可以将`spring.cloud.config.server.git.tryMasterBranch`设置为`false`。

#### [版本控制后端文件系统的使用](#_version_control_backend_filesystem_use)

|   |使用基于 VCS 的后端（Git，SVN），文件会被签出或克隆到本地文件系统中，<br/>默认情况下，它们会被放到系统临时目录中，前缀为`config-repo-`，例如，在 Linux 上，<br/>，它可能是`/tmp/config-repo-<randomid>`。<br/>某些操作系统[定期清理](https://serverfault.com/questions/377348/when-does-tmp-get-cleared/377349#377349)临时目录。<br/>这可能会导致意想不到的行为，例如丢失属性。，<br/>为了避免这个问题，将`spring.cloud.config.server.git.basedir`或`spring.cloud.config.server.svn.basedir`设置为不驻留在系统临时结构中的目录，从而更改 Config 服务器使用的目录。|
|---| |

#### [文件系统后端](#_file_system_backend)

配置服务器中还有一个“原生”配置文件，它不使用 Git，而是从本地 Classpath 或文件系统（你想用`spring.cloud.config.server.native.searchLocations`指向的任何静态 URL）加载配置文件。要使用本机配置文件，使用`spring.profiles.active=native`启动配置服务器。

|   |记住对文件资源使用`file:`前缀（没有前缀的默认情况通常是 Classpath）。<br/>与任何 Spring 引导配置一样，你可以嵌入`${}`-风格的环境占位符，但请记住，Windows 中的绝对路径需要额外的`/`（例如，`[file:///${user.home}/config-repo](file:///${user.home}/config-repo)`）。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |`searchLocations`的默认值与本地 Spring 引导应用程序（即`[classpath:/, classpath:/config,<br/>file:./, file:./config]`）相同。<br/>这不会将来自服务器的`application.properties`公开给所有客户端，因为服务器中存在的任何属性源在发送到客户端之前都会被删除。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |文件系统后端对于快速启动和测试非常有用。<br/>要在生产中使用它，你需要确保文件系统是可靠的，并在配置服务器的所有实例之间共享。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

搜索位置可以包含`{application}`、`{profile}`和`{label}`的占位符。通过这种方式，你可以隔离路径中的目录，并选择对你有意义的策略（例如每个应用程序的子目录或每个配置文件的子目录）。

如果在搜索位置中不使用占位符，那么这个存储库还会将 HTTP 资源的`{label}`参数附加到搜索路径的后缀中，因此，属性文件是从每个搜索位置**和**一个与标签同名的子目录加载的（在 Spring 环境中，标记属性优先）。因此，不带占位符的默认行为与添加以`/{label}/`结尾的搜索位置相同。例如，`file:/tmp/config`与`file:/tmp/config,file:/tmp/config/{label}`相同。可以通过设置`spring.cloud.config.server.native.addLabelLocations=false`来禁用此行为。

#### [保险库后端](#vault-backend)

Spring Cloud Config Server 还支持[Vault](https://www.vaultproject.io)作为后端。

Vault 是一种安全访问机密的工具。秘密是你想要严格控制访问的任何内容，例如 API 密钥、密码、证书和其他敏感信息。Vault 在提供严格的访问控制和记录详细的审计日志的同时，为任何秘密提供了统一的接口。

有关 Vault 的更多信息，请参见[跳马快速启动指南](https://learn.hashicorp.com/vault/?track=getting-started#getting-started)。

要使 Config 服务器能够使用 Vault 后端，你可以使用`vault`配置文件运行你的 Config 服务器。例如，在配置服务器的`application.properties`中，可以添加`spring.profiles.active=vault`。

默认情况下， Spring Cloud Config Server 使用基于令牌的身份验证来从 Vault 获取配置。Vault 还支持其他身份验证方法，如 Approle、LDAP、JWT、CloudFoundry、Kubernetes Auth。为了使用除令牌或 X-Config-Token 头以外的任何身份验证方法，我们需要在 Classpath 上具有 Spring Vault core，以便 Config 服务器可以将身份验证委派给该库。请将以下依赖项添加到你的配置服务器应用程序中。

`Maven (POM.xml)`

```
<dependencies>
	<dependency>
		<groupId>org.springframework.vault</groupId>
		<artifactId>spring-vault-core</artifactId>
	</dependency>
</dependencies>
```

`Gradle (build.gradle)`

```
dependencies {
    implementation "org.springframework.vault:spring-vault-core"
}
```

默认情况下，配置服务器假定你的 Vault 服务器运行在`[http://127.0.0.1:8200](http://127.0.0.1:8200)`。它还假定后端的名称是`secret`，键是`application`。所有这些默认值都可以在配置服务器的`application.properties`中进行配置。下表描述了可配置的保险库属性：

|姓名|Default Value|
|-----------------|-------------|
|主机|  127.0.0.1  |
|港口|    8200     |
|方案|    http     |
|后端|   secret    |
|DefaultKey| application |
|Profileseparator|      ,      |
|KVVersion|      1      |
|skipSslValidation|    false    |
|超时|      5      |
|名称空间|    null     |

|   |前一个表中的所有属性必须使用`spring.cloud.config.server.vault`作为前缀，或者放在复合配置的正确的保险库部分。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

所有可配置的属性都可以在`org.springframework.cloud.config.server.environment.VaultEnvironmentProperties`中找到。

|   |Vault0.10.0 引入了一个版本控制的键值后端（k/v 后端版本 2），该版本公开了与早期版本不同的 API，现在它需要在挂载路径和实际上下文路径之间设置`data/`，并在`data`对象中包装秘密。设置`spring.cloud.config.server.vault.kv-version=2`将考虑到这一点。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

可选地，存在对 Vault Enterprise`X-Vault-Namespace`头的支持。要将其发送到 Vault，请设置`namespace`属性。

在配置服务器运行时，你可以向服务器发出 HTTP 请求，以便从保险库后端取回值。要做到这一点，你需要为你的保险库服务器提供一个令牌。

首先，在保险库中放置一些数据，如以下示例所示：

```
$ vault kv put secret/application foo=bar baz=bam
$ vault kv put secret/myapp foo=myappsbar
```

其次，向配置服务器发出 HTTP 请求，以检索这些值，如下例所示：

`$ curl -X "GET" "http://localhost:8888/myapp/default" -H "X-Config-Token: yourtoken"`

你应该会看到类似于以下内容的响应：

```
{
   "name":"myapp",
   "profiles":[
      "default"
   ],
   "label":null,
   "version":null,
   "state":null,
   "propertySources":[
      {
         "name":"vault:myapp",
         "source":{
            "foo":"myappsbar"
         }
      },
      {
         "name":"vault:application",
         "source":{
            "baz":"bam",
            "foo":"bar"
         }
      }
   ]
}
```

客户机提供必要的身份验证以让 Config Server 与 Vault 对话的默认方式是设置 X-Config-Token 头。但是，你可以通过设置与 Spring Cloud Vault 相同的配置属性，省略标题并在服务器中配置身份验证。要设置的属性是`spring.cloud.config.server.vault.authentication`。应该将其设置为受支持的身份验证方法之一。你可能还需要设置特定于你使用的身份验证方法的其他属性，方法是使用与`spring.cloud.vault`相同的属性名称，而不是使用`spring.cloud.config.server.vault`前缀。有关更多详细信息，请参见[Spring Cloud Vault Reference Guide](https://cloud.spring.io/spring-cloud-vault/reference/html/#vault.config.authentication)。

|   |如果省略 X-Config-Token 头并使用服务器属性设置身份验证，则 Config 服务器应用程序需要对 Spring Vault 有一个额外的依赖项，以启用额外的身份验证选项。<br/>有关如何添加该依赖项，请参见[Spring Vault Reference Guide](https://docs.spring.io/spring-vault/docs/current/reference/html/#dependencies)。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### [多属性源](#_multiple_properties_sources)

在使用 Vault 时，你可以为应用程序提供多个属性源。例如，假设你已将数据写入 Vault 中的以下路径：

```
secret/myApp,dev
secret/myApp
secret/application,dev
secret/application
```

写入`secret/application`的属性可用于[所有使用配置服务器的应用程序](#_vault_server)。名称为`myApp`的应用程序将具有写为`secret/myApp`和`secret/application`的任何属性。当`myApp`启用`dev`配置文件时，写到上述所有路径的属性将对它可用，并且列表中第一个路径中的属性优先于其他路径。

#### [通过代理访问后端](#_accessing_backends_through_a_proxy)

配置服务器可以通过 HTTP 或 HTTPS 代理访问 Git 或 Vault 后端。此行为由`proxy.http`和`proxy.https`下的设置控制，用于 Git 或 Vault。这些设置是每个存储库设置的，因此，如果使用[复合环境存储库](#composite-environment-repositories)，则必须为组合中的每个后端单独配置代理设置。如果使用的网络需要为 HTTP 和 HTTPS URL 提供单独的代理服务器，则可以为单个后端配置 HTTP 和 HTTPS 代理设置。

下表描述了 HTTP 和 HTTPS 代理的代理配置属性。所有这些属性必须以`proxy.http`或`proxy.https`为前缀。

|  Property Name  |备注|
|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|    **host**     |代理的主机。|
|    **port**     |访问代理的端口。|
|**nonProxyHosts**|配置服务器应该访问代理之外的任何主机.如果同时为`proxy.http.nonProxyHosts`和`proxy.https.nonProxyHosts`提供了值，则将使用`proxy.http`值。|
|  **username**   |对代理进行身份验证的用户名。如果同时为`proxy.http.username`和`proxy.https.username`提供了值，则将使用`proxy.http`值。|
|  **password**   |用于对代理进行身份验证的密码。如果同时为`proxy.http.password`和`proxy.https.password`提供了值，则将使用`proxy.http`值。|

以下配置使用 HTTPS 代理访问 Git 存储库。

```
spring:
  profiles:
    active: git
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          proxy:
            https:
              host: my-proxy.host.io
              password: myproxypassword
              port: '3128'
              username: myproxyusername
              nonProxyHosts: example.com
```

#### [与所有应用程序共享配置](#_sharing_configuration_with_all_applications)

在所有应用程序之间共享配置取决于你所采用的方法，如以下主题所述：

* [基于文件的存储库](#spring-cloud-config-server-file-based-repositories)

* [保险库服务器](#spring-cloud-config-server-vault-server)

##### [基于文件的存储库](#spring-cloud-config-server-file-based-repositories)

对于基于文件的（Git、SVN 和 Native）存储库，文件名为`application*`（`application.properties`、`application.yml`、`application-*.properties`等）的资源在所有客户端应用程序之间共享。你可以使用这些文件名的资源来配置全局默认值，并在必要时让它们被特定于应用程序的文件覆盖。

[属性重写](#property-overrides)特性还可以用于设置全局默认值，占位符应用程序可以在本地覆盖它们。

|   |对于“本机”配置文件（本地文件系统后端），你应该使用一个不属于服务器自身配置的显式搜索位置。<br/>否则，默认搜索位置中的`application*`资源将被删除，因为它们是服务器的一部分。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### [保险库服务器](#spring-cloud-config-server-vault-server)

当使用 Vault 作为后端时，你可以通过在`secret/application`中放置配置来与所有应用程序共享配置。例如，如果你运行以下 Vault 命令，那么所有使用 Config 服务器的应用程序都将具有它们可用的属性`foo`和`baz`:

```
$ vault write secret/application foo=bar baz=bam
```

##### [CredHub 服务器](#_credhub_server)

当使用 Credhub 作为后端时，你可以通过将配置放置在`/application/`中或将其放置在应用程序的`default`配置文件中来与所有应用程序共享配置。例如，如果你运行下面的 credhub 命令，那么所有使用 Config 服务器的应用程序都将具有它们可用的属性`shared.color1`和`shared.color2`:

```
credhub set --name "/application/profile/master/shared" --type=json
value: {"shared.color1": "blue", "shared.color": "red"}
```

```
credhub set --name "/my-app/default/master/more-shared" --type=json
value: {"shared.word1": "hello", "shared.word2": "world"}
```

#### [AWS 秘密管理器](#_aws_secrets_manager)

当使用 AWS Secrets Manager 作为后端时，你可以通过将配置放置在`/application/`中或将其放置在应用程序的`default`配置文件中来与所有应用程序共享配置。例如，如果你使用以下键添加秘密，那么所有使用配置服务器的应用程序都将具有它们可用的属性`shared.foo`和`shared.bar`:

```
secret name = /secret/application-default/
```

```
secret value =
{
 shared.foo: foo,
 shared.bar: bar
}
```

or

```
secret name = /secret/application/
```

```
secret value =
{
 shared.foo: foo,
 shared.bar: bar
}
```

##### [AWS 参数存储](#_aws_parameter_store)

当使用 AWS 参数存储作为后端时，你可以通过在`/application`层次结构中放置属性来与所有应用程序共享配置。

例如，如果使用以下名称添加参数，那么所有使用配置服务器的应用程序都将具有它们可用的属性`foo.bar`和`fred.baz`:

```
/config/application/foo.bar
/config/application-default/fred.baz
```

#### [JDBC 后端](#_jdbc_backend)

Spring Cloud 配置服务器支持 JDBC（关系数据库）作为配置属性的后端。你可以通过向 Classpath 中添加`spring-jdbc`并使用`jdbc`配置文件或通过添加类型`JdbcEnvironmentRepository`的 Bean 来启用此功能。如果你包括对 Classpath 的正确依赖关系（有关此的更多详细信息，请参见用户指南），则 Spring 引导将配置数据源。

通过将`spring.cloud.config.server.jdbc.enabled`属性设置为`false`，可以禁用`JdbcEnvironmentRepository`的自动配置。

数据库需要有一个名为`PROPERTIES`的表，其中的列分别为`APPLICATION`、`PROFILE`和`LABEL`（具有通常的`Environment`含义），加上`KEY`和`VALUE`用于`Properties`样式中的键和值对。在 Java 中，所有字段都是 String 类型的，因此你可以使它们`VARCHAR`具有所需的任何长度。如果属性值来自名为`{application}-{profile}.properties`的 Spring 引导属性文件，则属性值的行为与它们的行为相同，包括所有的加密和解密，这些将作为后处理步骤应用（即，不直接在存储库实现中）。

#### [Redis 后端](#_redis_backend)

Spring Cloud Config Server 支持 Redis 作为配置属性的后端。你可以通过向[Spring Data Redis](https://spring.io/projects/spring-data-redis)添加依赖项来启用此功能。

POM.xml

```
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-redis</artifactId>
	</dependency>
</dependencies>
```

下面的配置使用 Spring data`RedisTemplate`来访问 Redis。我们可以使用`spring.redis.*`属性来覆盖默认的连接设置。

```
spring:
  profiles:
    active: redis
  redis:
    host: redis
    port: 16379
```

这些属性应该存储为散列中的字段。散列的名称应该与`spring.application.name`的属性或`spring.application.name`和`spring.profiles.active[n]`的连词相同。

```
HMSET sample-app server.port "8100" sample.topic.name "test" test.property1 "property1"
```

在运行位于散列上方可见的命令之后，散列应该包含以下带值的键：

```
HGETALL sample-app
{
  "server.port": "8100",
  "sample.topic.name": "test",
  "test.property1": "property1"
}
```

|   |当未指定配置文件时，将使用`default`。|
|---|----------------------------------------------------|

#### [AWS S3 后端](#_aws_s3_backend)

Spring Cloud 配置服务器支持 AWS S3 作为配置属性的后端。你可以通过向[亚马逊 S3 的 AWS Java SDK](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/examples-s3.html)添加依赖项来启用此功能。

POM.xml

```
<dependencies>
	<dependency>
		<groupId>com.amazonaws</groupId>
		<artifactId>aws-java-sdk-s3</artifactId>
	</dependency>
</dependencies>
```

以下配置使用 AWS S3 客户端访问配置文件。我们可以使用`spring.cloud.config.server.awss3.*`属性来选择存储配置的桶。

```
spring:
  profiles:
    active: awss3
  cloud:
    config:
      server:
        awss3:
          region: us-east-1
          bucket: bucket1
```

也可以使用`spring.cloud.config.server.awss3.endpoint`将 AWS URL 指定为你的 S3 服务的[覆盖标准端点](https://aws.amazon.com/blogs/developer/using-new-regions-and-endpoints/)。这允许支持 S3 的测试版区域，以及其他与 S3 兼容的存储 API。

使用[默认的 AWS 凭据提供商链](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html)找到凭据。支持版本控制和加密的桶，而无需进一步配置。

配置文件以`{application}-{profile}.properties`、`{application}-{profile}.yml`或`{application}-{profile}.json`的形式存储在你的 bucket 中。可以提供一个可选的标签来指定文件的目录路径。

|   |当未指定配置文件时，将使用`default`。|
|---|----------------------------------------------------|

#### [AWS 参数存储后端](#_aws_parameter_store_backend)

Spring Cloud 配置服务器支持 AWS 参数存储作为配置属性的后端。你可以通过向[面向 SSM 的 AWS Java SDK](https://github.com/aws/aws-sdk-java/tree/master/aws-java-sdk-ssm)添加依赖项来启用此功能。

POM.xml

```
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-ssm</artifactId>
</dependency>
```

以下配置使用 AWS SSM 客户端访问参数。

```
spring:
  profiles:
    active: awsparamstore
  cloud:
    config:
      server:
        awsparamstore:
          region: eu-west-2
          endpoint: https://ssm.eu-west-2.amazonaws.com
          origin: aws:parameter:
          prefix: /config/service
          profile-separator: _
          recursive: true
          decrypt-values: true
          max-results: 5
```

下表描述了 AWS 参数存储配置属性。

|    Property Name    |Required|   Default Value    |备注|
|---------------------|--------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|     **region**      |   no   |                    |AWS 参数存储客户端要使用的区域。如果没有显式设置，那么 SDK 将尝试使用[默认区域提供器链](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-region-selection.html#default-region-provider-chain)来确定要使用的区域。|
|    **endpoint**     |   no   |                    |AWS SSM 客户端入口点的 URL。这可以用来为 API 请求指定一个替代端点。|
|     **origin**      |   no   |`aws:ssm:parameter:`|添加到属性源名称中以显示其来源的前缀。|
|     **prefix**      |   no   |     `/config`      |前缀表示从 AWS 参数存储区加载的每个属性的参数层次结构中的 L1 级别。|
|**profile-separator**|   no   |        `-`         |将附加的配置文件与上下文名称分隔开的字符串。|
|    **recursive**    |   no   |       `true`       |标志来指示对层次结构中所有 AWS 参数的检索。|
| **decrypt-values**  |   no   |       `true`       |标志来指示对所有 AWS 参数的检索，并对其值进行解密。|
|   **max-results**   |   no   |        `10`        |AWS 参数存储 API 调用要返回的最大项数。|

AWS 参数存储 API 凭据是使用[默认凭据提供器链](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default)确定的。已支持版本控制的参数，其默认行为是返回最新版本。

|   |* 当没有指定应用程序`application`为默认值时，并且当没有指定配置文件时`default`被使用。<br/><br/>*`awsparamstore.prefix`的有效值必须从前斜杠开始，然后是一个或多个有效的路径段，否则将为空。<br/><br/>*`awsparamstore.profile-separator`的有效值只能包含点，破折号和下划线。<br/><br/>*`awsparamstore.max-results`的有效值必须在**[1, 10]**范围内。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### [AWS Secrets Manager 后端](#_aws_secrets_manager_backend)

Spring Cloud Config Server 支持[AWS 秘密管理器](https://aws.amazon.com/secrets-manager/)作为配置属性的后端。你可以通过向[用于 Secrets Manager 的 AWS Java SDK](https://github.com/aws/aws-sdk-java/tree/master/aws-java-sdk-secretsmanager)添加依赖项来启用此功能。

POM.xml

```
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-secretsmanager</artifactId>
</dependency>
```

以下配置使用 AWS Secrets Manager 客户端访问机密。

```
spring:
  profiles:
  	active: awssecretsmanager
  cloud:
    config:
      server:
        aws-secretsmanager:
          region: us-east-1
          endpoint: https://us-east-1.console.aws.amazon.com/
          origin: aws:secrets:
          prefix: /secret/foo
          profileSeparator: _
```

AWS Secrets Manager API 凭据是使用[默认凭据提供器链](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default)确定的。

|   |* 当没有指定应用程序时`application`是默认值，当没有指定配置文件时，使用`default`。|
|---|--------------------------------------------------------------------------------------------------------------------|

#### [Credhub 后端](#_credhub_backend)

Spring Cloud Config Server 支持[CredHub](https://docs.cloudfoundry.org/credhub)作为配置属性的后端。你可以通过向[Spring CredHub](https://spring.io/projects/spring-credhub)添加依赖项来启用此功能。

POM.xml

```
<dependencies>
	<dependency>
		<groupId>org.springframework.credhub</groupId>
		<artifactId>spring-credhub-starter</artifactId>
	</dependency>
</dependencies>
```

以下配置使用 Mutual TLS 访问 credhub:

```
spring:
  profiles:
    active: credhub
  cloud:
    config:
      server:
        credhub:
          url: https://credhub:8844
```

这些属性应该以 JSON 的形式存储，例如：

```
credhub set --name "/demo-app/default/master/toggles" --type=json
value: {"toggle.button": "blue", "toggle.link": "red"}
```

```
credhub set --name "/demo-app/default/master/abs" --type=json
value: {"marketing.enabled": true, "external.enabled": false}
```

所有名称为`spring.cloud.config.name=demo-app`的客户机应用程序都将具有以下可用属性：

```
{
    toggle.button: "blue",
    toggle.link: "red",
    marketing.enabled: true,
    external.enabled: false
}
```

|   |当未指定配置文件时，将使用`default`；当未指定标签时，将使用`master`作为默认值。<br/>注意：添加到`application`的值将被所有应用程序共享。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### [OAuth 2.0](#_oauth_2_0)

你可以使用[OAuth 2.0](https://oauth.net/2/)作为提供者进行身份验证。

pom.xml

```
<dependencies>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-config</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-oauth2-client</artifactId>
	</dependency>
</dependencies>
```

以下配置使用 OAuth2.0 和 UAA 来访问 credhub:

```
spring:
  profiles:
    active: credhub
  cloud:
    config:
      server:
        credhub:
          url: https://credhub:8844
          oauth2:
            registration-id: credhub-client
  security:
    oauth2:
      client:
        registration:
          credhub-client:
            provider: uaa
            client-id: credhub_config_server
            client-secret: asecret
            authorization-grant-type: client_credentials
        provider:
          uaa:
            token-uri: https://uaa:8443/oauth/token
```

|   |使用的 UAA 客户机 ID 应该有`credhub.read`作为作用域。|
|---|-----------------------------------------------------------|

#### [复合环境存储库](#composite-environment-repositories)

在某些场景中，你可能希望从多个环境存储库中提取配置数据。为此，你可以在配置服务器的应用程序属性或 YAML 文件中启用`composite`配置文件。例如，如果你希望从一个 Subversion 存储库以及两个 Git 存储库中提取配置数据，那么可以为配置服务器设置以下属性：

```
spring:
  profiles:
    active: composite
  cloud:
    config:
      server:
        composite:
        -
          type: svn
          uri: file:///path/to/svn/repo
        -
          type: git
          uri: file:///path/to/rex/git/repo
        -
          type: git
          uri: file:///path/to/walter/git/repo
```

使用此配置，优先级由`composite`键下列出存储库的顺序决定。在上面的示例中，首先列出了 Subversion 存储库，因此在 Subversion 存储库中找到的值将覆盖在一个 Git 存储库中为相同属性找到的值。在`rex`Git 存储库中找到的值将在`walter`Git 存储库中为相同属性找到的值之前使用。

如果只想从不同类型的存储库中提取配置数据，那么可以在配置服务器的应用程序属性或 YAML 文件中启用相应的配置文件，而不是`composite`配置文件。例如，如果希望从单个 Git 存储库和单个 HashiCorpVault 服务器中提取配置数据，则可以为配置服务器设置以下属性：

```
spring:
  profiles:
    active: git, vault
  cloud:
    config:
      server:
        git:
          uri: file:///path/to/git/repo
          order: 2
        vault:
          host: 127.0.0.1
          port: 8200
          order: 1
```

使用此配置，可以通过`order`属性来确定优先级。你可以使用`order`属性来指定所有存储库的优先级顺序。`order`属性的数值越低，它的优先级就越高。存储库的优先级顺序有助于解决包含相同属性的值的存储库之间的任何潜在冲突。

|   |如果你的组合环境像前面的示例一样包含一个 Vault 服务器，那么你必须在向配置服务器提出的每个请求中都包含一个 Vault 令牌。见[保险库后端](#vault-backend)。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |当从环境存储库检索值时，任何类型的失败都会导致整个复合环境失败。<br/>如果你希望在存储库失败时继续进行复合，则可以将`spring.cloud.config.server.failOnCompositeError`设置为`false`。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |在使用复合环境时，所有存储库都包含相同的标签是很重要的，<br/>如果你的环境与前面的示例中的环境类似，并且你使用`master`标签请求配置数据，但是 Subversion 存储库不包含一个名为`master`的分支，整个请求都失败了。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### [自定义复合环境存储库](#_custom_composite_environment_repositories)

除了使用 Spring Cloud 中的一个环境存储库外，还可以提供你自己的`EnvironmentRepository` Bean，作为复合环境的一部分。要做到这一点，你的 Bean 必须实现`EnvironmentRepository`接口。如果希望在复合环境中控制自定义`EnvironmentRepository`的优先级，还应该实现`Ordered`接口并覆盖`getOrdered`方法。如果你没有实现`Ordered`接口，那么你的`EnvironmentRepository`将获得最低的优先级。

#### [属性重写](#property-overrides)

配置服务器具有“重写”功能，允许操作员向所有应用程序提供配置属性。使用普通 Spring 引导挂钩的应用程序不会意外地更改重写的属性。要声明重写，请将名称-值对的映射添加到`spring.cloud.config.server.overrides`，如下例所示：

```
spring:
  cloud:
    config:
      server:
        overrides:
          foo: bar
```

前面的示例使所有配置客户机的应用程序读取`foo=bar`，这与它们自己的配置无关。

|   |配置系统不能强制应用程序以任何特定方式使用配置数据。<br/>因此，重写是不可执行的。<br/>但是，它们确实为 Spring Cloud 配置客户机提供了有用的默认行为。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |通常， Spring 具有`${}`的环境占位符可以通过使用反斜杠（`\`）来转义（并在客户机上解析），以转义`$`或`{`。<br/>例如，`\${app.foo:bar}`可解析为`bar`，除非应用程序提供自己的`app.foo`。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |在 YAML 中，不需要转义反斜杠本身。<br/>但是，在属性文件中，在服务器上配置重写时，确实需要转义反斜杠。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

通过在远程存储库中设置`spring.cloud.config.overrideNone=true`标志（默认值为 false），你可以将客户机中所有重写的优先级更改为更像默认值，让应用程序在环境变量或系统属性中提供它们自己的值。

### [健康指标](#_health_indicator)

Config Server 附带一个健康指示器，用于检查配置的`EnvironmentRepository`是否工作。默认情况下，它向`EnvironmentRepository`请求名为`app`的应用程序、`default`配置文件和`EnvironmentRepository`实现提供的默认标签。

你可以将健康指示器配置为检查更多的应用程序以及自定义配置文件和自定义标签，如下例所示：

```
spring:
  cloud:
    config:
      server:
        health:
          repositories:
            myservice:
              label: mylabel
            myservice-dev:
              name: myservice
              profiles: development
```

你可以通过设置`management.health.config.enabled=false`禁用健康指示器。

### [Security](#_security)

你可以以任何对你有意义的方式（从物理网络安全到 OAuth2 承载令牌）保护你的配置服务器，因为 Spring 安全性和 Spring 启动为许多安全安排提供了支持。

要使用默认的 Spring 启动配置的 HTTP 基本安全性，在 Classpath 上包括 Spring 安全性（例如，通过`spring-boot-starter-security`）。默认的是`user`的用户名和随机生成的密码。随机密码在实践中是没有用的，因此我们建议你配置密码（通过设置`spring.security.user.password`）并对其进行加密（请参阅下面的操作说明）。

### [执行器和安全性](#_actuator_and_security)

|   |一些平台配置健康检查或类似的东西，并指向`/actuator/health`或其他执行器端点。如果致动器不是配置服务器的依赖项，则对`/actuator/`**的请求将匹配配置服务器 API`/{application}/{label}`可能泄漏安全信息。在这种情况下，请记住添加`spring-boot-starter-actuator`依赖项，并对用户进行配置，使调用`/actuator/`** 的用户无法访问`/{application}/{label}`上的配置服务器 API。|
|---| |

### [加密和解密](#_encryption_and_decryption)

|   |要使用加密和解密功能，你需要在你的 JVM 中安装全强度 JCE（默认情况下不包括它）。<br/>你可以从 Oracle 下载“Java Cryptography Extension（JCE）Unlimited Strength Juridictory Policy Files”，并按照安装说明（基本上，你需要用下载的文件替换 JRElib/security 目录中的两个策略文件）。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

如果远程属性源包含加密的内容（以`{cipher}`开头的值），则在通过 HTTP 发送到客户机之前对它们进行解密。这种设置的主要优点是，当属性值“处于静止状态”（例如，在 Git 存储库中）时，它们不需要是纯文本的。如果一个值不能解密，则从属性源中删除它，并添加一个附加的属性，该属性使用相同的键，但前缀为`invalid`和一个表示“不适用”的值（通常是`<n/a>`）。这在很大程度上是为了防止密码文本被用作密码而意外泄露。

如果你为配置客户机应用程序设置了一个远程配置存储库，那么它可能包含一个`application.yml`，类似于以下内容：

application.yml

```
spring:
  datasource:
    username: dbuser
    password: '{cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ'
```

`application.properties`文件中的加密值不能用引号包装。否则，该值不会被解密。下面的示例显示了可以工作的值：

application.properties

```
spring.datasource.username: dbuser
spring.datasource.password: {cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ
```

你可以将这个纯文本安全地推送到一个共享的 Git 存储库，并且秘密密码仍然受到保护。

服务器还公开`/encrypt`和`/decrypt`端点（假设这些端点是安全的，并且仅由授权的代理访问）。如果编辑远程配置文件，可以使用配置服务器通过发布到`/encrypt`端点来加密值，如下例所示：

```
$ curl localhost:8888/encrypt -s -d mysecret
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
```

|   |如果你正在使用 curl 进行测试，那么使用`--data-urlencode`（而不是`-d`）并在该值前缀进行加密，使用`=`（curl 需要这样做）或设置显式`Content-Type: text/plain`，以确保 curl 在有特殊字符时正确地编码数据（’+’特别棘手）。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |一定不要在加密值中包含任何 curl 命令统计信息，这就是为什么示例使用`-s`选项来使它们保持沉默。将值输出到文件中可以帮助避免此问题。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

逆操作也可以通过`/decrypt`进行（如果服务器配置了对称密钥或全密钥对），如以下示例所示：

```
$ curl localhost:8888/decrypt -s -d 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret
```

获取加密值，并在将其放入 YAML 或 Properties 文件之前以及提交并将其推送到远程（可能不安全）存储之前添加`{cipher}`前缀。

`/encrypt`和`/decrypt`端点也都接受`/*/{application}/{profiles}`形式的路径，当客户调用主环境资源时，可以使用该路径在每个应用程序（名称）和每个配置文件的基础上控制加密。

|   |要以这种细粒度的方式控制加密，还必须提供类型`@Bean`的`@Bean`，该类型的`TextEncryptorLocator`根据名称和配置文件创建不同的加密器。<br/>默认情况下提供的加密器不会这样做（所有加密都使用相同的密钥）。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

`spring`命令行客户端（安装了 Spring Cloud CLI 扩展）也可用于加密和解密，如以下示例所示：

```
$ spring encrypt mysecret --key foo
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret
```

要在文件中使用密钥（例如用于加密的 RSA 公钥），请在密钥值前加上“@”并提供文件路径，如以下示例所示：

```
$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
```

|   |`--key`参数是强制性的（尽管有`--`前缀）。|
|---|-----------------------------------------------------------------|

### [密钥管理](#_key_management)

配置服务器可以使用对称（共享）密钥或非对称（RSA 密钥对）密钥。非对称选择在安全性方面更好，但是使用对称密钥通常更方便，因为它是在`bootstrap.properties`中配置的单个属性值。

要配置一个对称密钥，你需要将`encrypt.key`设置为一个秘密字符串（或者使用`ENCRYPT_KEY`环境变量将其排除在纯文本配置文件之外）。

|   |不能使用`encrypt.key`配置非对称密钥。|
|---|-----------------------------------------------------------|

要配置非对称密钥，请使用密钥存储库（例如，由 JDK 附带的`keytool`实用程序创建）。密钥存储库属性是`encrypt.keyStore.*`，而`*`等于

|         Property          |说明|
|---------------------------|--------------------------------------------------|
|`encrypt.keyStore.location`|包含`Resource`位置|
|`encrypt.keyStore.password`|持有解锁密钥存储库的密码|
| `encrypt.keyStore.alias`  |标识要使用的存储区中的哪个键|
|  `encrypt.keyStore.type`  |要创建的密钥存储库的类型。默认值为`jks`。|

加密是用公钥完成的，解密需要私钥。因此，原则上，如果你只想加密（并且准备好自己在本地使用私钥解密这些值），那么你只能在服务器中配置公钥。在实践中，你可能不希望在本地进行解密，因为它将密钥管理过程分散到所有客户机，而不是将其集中在服务器中。另一方面，如果你的配置服务器相对不安全，并且只有少数客户机需要加密的属性，那么它可能是一个有用的选择。

### [创建用于测试的密钥库](#_creating_a_key_store_for_testing)

要创建用于测试的密钥库，你可以使用类似于以下命令的命令：

```
$ keytool -genkeypair -alias mytestkey -keyalg RSA \
  -dname "CN=Web Server,OU=Unit,O=Organization,L=City,S=State,C=US" \
  -keypass changeme -keystore server.jks -storepass letmein
```

|   |当使用 JDK11 或更高版本时，当使用上面的命令时，你可能会得到以下警告。在这种情况下，<br/>可能需要确保`keypass`和`storepass`值匹配。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

```
Warning:  Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified -keypass value.
```

在 Classpath（例如）中放置`server.jks`文件，然后在`bootstrap.yml`中为配置服务器创建以下设置：

```
encrypt:
  keyStore:
    location: classpath:/server.jks
    password: letmein
    alias: mytestkey
    secret: changeme
```

### [使用多个键和键旋转](#_using_multiple_keys_and_key_rotation)

除了加密属性值中的`{cipher}`前缀外，配置服务器还在（base64 编码的）密码文本开始之前查找零个或更多的`{name:value}`前缀。这些密钥被传递给`TextEncryptorLocator`，它可以执行所需的任何逻辑来为密码定位`TextEncryptor`。如果你已经配置了一个密钥存储库（`encrypt.keystore.location`），则默认定位器将查找由`key`前缀提供的别名的密钥，并使用类似于以下内容的密码文本：

```
foo:
  bar: `{cipher}{key:testkey}...`
```

定位器查找一个名为“TestKey”的键。也可以通过在前缀中使用`{secret:…​}`值来提供秘密。但是，如果没有提供，默认情况是使用 keystore 密码（这是你在构建 keystore 而不指定秘密时获得的密码）。如果你确实提供了一个秘密，则还应该使用自定义`SecretLocator`对该秘密进行加密。

当密钥仅用于加密几个字节的配置数据时（也就是说，它们不在其他地方使用），出于加密的原因，几乎不需要旋转密钥。但是，你可能偶尔需要更改密钥（例如，在发生安全漏洞的情况下）。在这种情况下，所有客户机都需要更改其源配置文件（例如，在 Git 中），并在所有密码中使用新的`{key:…​}`前缀。请注意，客户端需要首先检查密钥别名在配置服务器密钥存储库中是否可用。

|   |如果你想让配置服务器处理所有的加密和解密，`{name:value}`前缀也可以作为纯文本添加到`/encrypt`端点。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### [服务加密的属性](#_serving_encrypted_properties)

有时，你希望客户机在本地解密配置，而不是在服务器中进行解密。在这种情况下，如果你提供`encrypt.*`配置来定位一个密钥，那么你仍然可以拥有`/encrypt`和`/decrypt`端点，但是你需要通过将`spring.cloud.config.server.encrypt.enabled=false`放在`bootstrap.[yml|properties]`中来显式地关闭输出属性的解密。如果你不关心端点，那么如果你不配置键或启用的标志，那么它应该可以工作。

## [提供替代格式](#_serving_alternative_formats)

来自环境端点的默认 JSON 格式非常适合 Spring 应用程序使用，因为它直接映射到`Environment`抽象。如果你愿意，可以通过向资源路径添加一个后缀（“.yml”、“.yaml”或“.properties”）来使用与 YAML 或 Java 属性相同的数据。这对于不关心 JSON 端点的结构或它们提供的额外元数据的应用程序来说是有用的（例如，不使用 Spring 的应用程序可能会受益于这种方法的简单性）。

YAML 和 Properties 表示有一个额外的标志（作为布尔查询参数提供），以表示源文档（在标准 Spring 形式中）中的占位符应该在呈现之前在输出中解析（如果可能的话）。对于不了解 Spring 占位符约定的消费者来说，这是一个有用的特性。

|   |在使用 YAML 或 Properties 格式时有一些限制，主要是与元数据的丢失有关，<br/>例如，JSON 被构建为一个有序的属性源列表，其名称与源相关，<br/>YAML 和 Properties 表单合并成一个映射，即使值的原点有多个源，并且原始源文件的名称丢失。<br/>同样，YAML 表示也不一定是备份存储库中 YAML 源的忠实表示。它是由一个平面属性源列表构建的，并且必须对键的形式进行假设。|
|---| |

## [提供纯文本](#_serving_plain_text)

与使用`Environment`抽象（或 YAML 或 Properties 格式的替代表示形式之一）不同，你的应用程序可能需要针对其环境定制的通用纯文本配置文件。配置服务器通过位于`/{application}/{profile}/{label}/{path}`的附加端点提供这些，其中`application`、`profile`和`label`与常规环境端点具有相同的含义，但是`path`是一个文件名的路径（例如`log.xml`）。该端点的源文件的定位方式与环境端点的定位方式相同。相同的搜索路径用于属性和 YAML 文件。然而，不是聚合所有匹配的资源，而是只返回第一个匹配的资源。

在找到资源之后，通过使用有效的`Environment`表示提供的应用程序名称、配置文件和标签，以正常格式（`${…​}`）的占位符进行解析。通过这种方式，资源端点与环境端点紧密集成。

|   |与用于环境配置的源文件一样，`profile`用于解析文件名。<br/>因此，如果你想要一个配置文件特定的文件，`/*/development/*/logback.xml`可以通过一个名为`logback-development.xml`的文件进行解析（优先于`logback.xml`）。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |如果不想提供`label`并让服务器使用默认标签，则可以提供一个`useDefaultLabel`请求参数。<br/>因此，前面的`default`配置文件示例可以是`/sample/default/nginx.conf?useDefaultLabel`。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

目前， Spring Cloud Config 可以为 Git、SVN、原生后台和 AWS S3 提供明文服务。对 Git、SVN 和本机后台的支持是相同的。AWS S3 的工作原理略有不同。以下几节展示了每一项的工作原理：

* [Git、SVN 和本机后端](#spring-cloud-config-serving-plain-text-git-svn-native-backends)

* [AWS S3](#spring-cloud-config-serving-plain-text-aws-s3)

### [Git、SVN 和本机后端](#spring-cloud-config-serving-plain-text-git-svn-native-backends)

考虑以下用于 Git 或 SVN 存储库或本机后端的示例：

```
application.yml
nginx.conf
```

`nginx.conf`可能类似于以下清单：

```
server {
    listen              80;
    server_name         ${nginx.server.name};
}
```

`application.yml`可能类似于以下清单：

```
nginx:
  server:
    name: example.com
---
spring:
  profiles: development
nginx:
  server:
    name: develop.com
```

资源`/sample/default/master/nginx.conf`如下：

```
server {
    listen              80;
    server_name         example.com;
}
```

`/sample/development/master/nginx.conf`可能如下：

```
server {
    listen              80;
    server_name         develop.com;
}
```

### [AWS S3](#spring-cloud-config-serving-plain-text-aws-s3)

要为 AWS S3 启用纯文本服务，Config Server 应用程序需要包括对 Spring Cloud AWS 的依赖。有关如何设置该依赖项的详细信息，请参见[Spring Cloud AWS Reference Guide](https://cloud.spring.io/spring-cloud-static/spring-cloud-aws/2.1.3.RELEASE/single/spring-cloud-aws.html#_spring_cloud_aws_maven_dependency_management)。然后需要配置 Spring Cloud AWS，如[Spring Cloud AWS Reference Guide](https://cloud.spring.io/spring-cloud-static/spring-cloud-aws/2.1.3.RELEASE/single/spring-cloud-aws.html#_configuring_credentials)中所述。

### [解密纯文本](#_decrypting_plain_text)

默认情况下，纯文本文件中的加密值不会被解密。为了启用对纯文本文件的解密，请在`bootstrap.[yml|properties]`中设置`spring.cloud.config.server.encrypt.enabled=true`和`spring.cloud.config.server.encrypt.plainTextEncrypt=true`。

|   |解密纯文本文件仅支持 YAML、JSON 和 Properties 文件扩展名。|
|---|---------------------------------------------------------------------------------------------|

如果启用了此功能，并且请求了不受支持的文件扩展，则文件中的任何加密值都不会被解密。

## [嵌入配置服务器](#_embedding_the_config_server)

配置服务器作为独立应用程序运行得最好。但是，如果需要，你可以将其嵌入到另一个应用程序中。要做到这一点，请使用`@EnableConfigServer`注释。在这种情况下，一个名为`spring.cloud.config.server.bootstrap`的可选属性是有用的。它是一个标志，指示服务器是否应该从自己的远程存储库中配置自己。默认情况下，标志是关闭的，因为它可能会延迟启动。然而，当嵌入到另一个应用程序中时，以与任何其他应用程序相同的方式初始化是有意义的。当将`spring.cloud.config.server.bootstrap`设置为`true`时，还必须使用[复合环境存储库配置](#composite-environment-repositories)。例如

```
spring:
  application:
    name: configserver
  profiles:
    active: composite
  cloud:
    config:
      server:
        composite:
          - type: native
            search-locations: ${HOME}/Desktop/config
        bootstrap: true
```

|   |如果使用 Bootstrap 标志，则配置服务器需要在`bootstrap.yml`中配置其名称和存储库 URI。|
|---|-------------------------------------------------------------------------------------------------------------------------|

要更改服务器端点的位置，可以（可选地）设置`spring.cloud.config.server.prefix`（例如，`/config`），以在前缀下提供资源。前缀应该以`/`开始，而不是结束。它被应用到配置服务器中的`@RequestMappings`（即在 Spring 引导`server.servletPath`和`server.contextPath`前缀下）。

如果你想直接从后端存储库（而不是从配置服务器）读取应用程序的配置，那么基本上需要一个没有端点的嵌入式配置服务器。你可以通过不使用`@EnableConfigServer`注释（set`spring.cloud.config.server.bootstrap=true`）来完全关闭端点。

## [Push Notifications and Spring Cloud Bus](#_push_notifications_and_spring_cloud_bus)

许多源代码存储库提供商（如 GitHub、GitLab、Gitea、Gitee、GOGS 或 Bitbucket）通过 Webhook 通知你存储库中的更改。你可以通过提供者的用户界面将 Webhook 配置为一个 URL 和一组你感兴趣的事件。例如，[Github](https://developer.github.com/v3/activity/events/types/#pushevent)使用到 Webhook 的 POST，其中的 JSON 主体包含提交列表，并将标题（`X-Github-Event`）设置为`push`。如果你在`spring-cloud-config-monitor`库上添加了一个依赖项，并激活了配置服务器中的 Spring Cloud 总线，那么将启用一个`/monitor`端点。

当 Webhook 被激活时，配置服务器发送一个`RefreshRemoteApplicationEvent`，目标是它认为可能已经更改的应用程序。变更检测可以被战略化。但是，默认情况下，它会查找与应用程序名称匹配的文件中的更改（例如，`foo.properties`是针对`foo`应用程序的，而`application.properties`是针对所有应用程序的）。当你想要重写该行为时使用的策略是`PropertyPathNotificationExtractor`，它接受请求头和主体作为参数，并返回已更改的文件路径列表。

对于 GitHub、GitLab、Gitea、Gitee、Gogs 或 Bitbucket，默认配置是开箱即用的。除了来自 GitHub、GitLab、Gitee 或 Bitbucket 的 JSON 通知外，你还可以通过使用`/monitor`模式中的表单编码主体参数发布到`path={application}`来触发更改通知。这样做会向匹配`{application}`模式（其中可能包含通配符）的应用程序广播。

|   |只有当`spring-cloud-bus`在配置服务器和客户端应用程序中都激活`spring-cloud-bus`时，才会传输`RefreshRemoteApplicationEvent`。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |默认配置还会检测本地 Git 存储库中的文件系统更改。在这种情况下，不使用 Webhook。但是，一旦编辑配置文件，就会广播刷新。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## [Spring Cloud Config Client](#_spring_cloud_config_client)

Spring 引导应用程序可以立即利用 Spring 配置服务器（或由应用程序开发人员提供的其他外部属性源）。它还获取了一些与`Environment`更改事件相关的其他有用特性。

### [Spring Boot Config Data Import](#config-data-import)

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

要可选地连接到配置服务器，请在应用程序中设置以下内容：

application.properties

```
spring.config.import=optional:configserver:
```

这将在“http://localhost:8888”的默认位置连接到配置服务器。如果无法连接到 Config 服务器，删除`optional:`前缀将导致 Config 客户机失败。要更改配置服务器的位置，可以设置`spring.cloud.config.uri`，也可以将 URL 添加到`spring.config.import`语句中，例如，`spring.config.import=optional:configserver:http://myhost:8888`。导入属性中的位置优先于 URI 属性。

|   |通过`spring.config.import`导入 Spring 引导配置数据方法所需的`bootstrap`文件（属性或 YAML）是**不是**。|
|---|--------------------------------------------------------------------------------------------------------------------------------------|

### [配置第一引导程序](#config-first-bootstrap)

要使用传统的 Bootstrap 方式连接到 Config 服务器，必须通过属性或`spring-cloud-starter-bootstrap`启动器启用 Bootstrap。该属性是`spring.cloud.bootstrap.enabled=true`。它必须设置为系统属性或环境变量。一旦启动了引导程序，在 Classpath 上使用 Spring Cloud Config 客户端的任何应用程序都将按如下方式连接到 Config 服务器：当一个 Config 客户端启动时，它将绑定到 Config 服务器（通过`spring.cloud.config.uri`Bootstrap 配置属性）并使用远程属性源初始化 Spring `Environment`。

这种行为的最终结果是，所有想要使用配置服务器的客户端应用程序都需要一个`bootstrap.yml`（或一个环境变量），其服务器地址设置为`spring.cloud.config.uri`（默认为“http://localhost:8888”）。

#### [发现第一查找](#discovery-first-bootstrap)

|   |除非你使用[配置第一引导程序](#config-first-bootstrap)，否则你将需要在配置属性中使用`spring.config.import`属性，并使用`optional:`前缀。<br/>例如，`spring.config.import=optional:configserver:`。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

如果使用`DiscoveryClient`实现，例如 Spring Cloud Netflix 和 Eureka 服务 Discovery 或 Spring Cloud Consul，则可以将配置服务器注册到该发现服务中。

如果你更喜欢使用`DiscoveryClient`来定位配置服务器，那么可以通过设置`spring.cloud.config.discovery.enabled=true`（默认值是`false`）来实现。例如，使用 Spring Cloud Netflix，你需要定义 Eureka 服务器地址（例如，在`eureka.client.serviceUrl.defaultZone`中）。使用此选项的价格是在启动时进行额外的网络往返，以定位服务注册。好处是，只要发现服务是一个固定点，配置服务器就可以更改其坐标。默认的服务 ID 是`configserver`，但是你可以在客户机上通过设置`spring.cloud.config.discovery.serviceId`来更改这个 ID（在服务器上，以服务的通常方式，例如通过设置`spring.application.name`）。

发现客户机实现都支持某种元数据映射（例如，对于 Eureka，我们有`eureka.instance.metadataMap`）。配置服务器的一些附加属性可能需要在其服务注册元数据中进行配置，以便客户端能够正确地连接。如果配置服务器使用 HTTP Basic 进行了安全保护，则可以将凭据配置为`user`和`password`。此外，如果配置服务器具有上下文路径，则可以设置`configPath`。例如，下面的 YAML 文件是针对作为 Eureka 客户机的配置服务器的：

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

#### [使用 Eureka 和 WebClient 的 Discovery First Bootstrap](#_discovery_first_bootstrap_using_eureka_and_webclient)

如果你使用 Spring Cloud Netflix 中的 Eureka，并且还希望使用而不是 Jersey 或，则需要在你的 Classpath 上包括以及设置。

### [配置客户端快速失败](#config-client-fail-fast)

在某些情况下，如果服务无法连接到配置服务器，你可能希望启动失败。如果这是期望的行为，请设置 BootStrap 配置属性`spring.cloud.config.fail-fast=true`，以使客户端在出现异常时停止。

|   |要使用`spring.config.import`获得类似的功能，只需省略`optional:`前缀。|
|---|----------------------------------------------------------------------------------------------|

### [配置客户端重试](#config-client-retry)

如果你希望配置服务器在应用程序启动时偶尔不可用，那么可以在出现故障后让它继续尝试。首先，需要设置`spring.cloud.config.fail-fast=true`。然后你需要将`spring-retry`和`spring-boot-starter-aop`添加到你的 Classpath。默认的行为是重试六次，初始退避间隔为 1000ms，后续退避的指数乘数为 1.1。你可以通过设置`spring.cloud.config.retry.*`配置属性来配置这些属性（以及其他属性）。

|   |要完全控制重试行为并使用遗留引导程序，请添加`RetryOperationsInterceptor`类型的`@Bean`，ID 为`configServerRetryInterceptor`。<br/> Spring 重试有一个`RetryInterceptorBuilder`支持创建一个。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### [Config Client Retry with spring.config.import](#_config_client_retry_with_spring_config_import)

Retry 与 Spring boot`spring.config.import`语句一起工作，正常属性也可以工作。但是，如果导入语句位于配置文件中，例如`应用程序-prod.properties`，那么你需要一种不同的方式来配置重试。需要将配置作为 URL 参数放置在导入语句上。

application-prod.properties

```
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.*`配置属性。

### [定位远程配置资源](#_locating_remote_configuration_resources)

配置服务提供来自`/{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 服务器实现，它可以是 Git 标签、分支名称或提交 ID。标签也可以作为逗号分隔的列表提供。在这种情况下，将逐个尝试列表中的项目，直到成功。在处理一个特性分支时，这种行为可能是有用的。例如，你可能希望将配置标签与你的分支对齐，但将其设置为可选的（在这种情况下，使用`spring.cloud.config.label=myfeature,develop`）。

### [为配置服务器指定多个 URL](#_specifying_multiple_urls_for_the_config_server)

为了确保在部署了多个配置服务器实例并预期一个或多个实例不时不可用时具有高可用性，你可以指定多个 URL（在`spring.cloud.config.uri`属性下作为逗号分隔的列表），或者让你的所有实例在像 Eureka 这样的服务注册中心中注册（如果使用发现优先引导模式）。请注意，这样做仅在配置服务器不运行时（即应用程序退出时）或发生连接超时时时时才能确保高可用性。例如，如果 Config 服务器返回 500（内部服务器错误）响应，或者 Config 客户机从 Config 服务器接收 401（由于错误的凭据或其他原因），Config 客户机不会尝试从其他 URL 获取属性。这类错误表示用户问题，而不是可用性问题。

如果你在配置服务器上使用 HTTP Basic Security，那么目前只有在你在`spring.cloud.config.uri`属性下指定的每个 URL 中嵌入凭据时，才可能支持 per-config Server auth 凭据。如果使用任何其他类型的安全机制，则无法（当前）支持每个配置服务器的身份验证和授权。

### [配置超时](#_configuring_timeouts)

如果你想配置超时阈值：

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

* 可以使用属性`spring.cloud.config.request-connect-timeout`配置连接超时。

### [Security](#_security_2)

如果你在服务器上使用 HTTP Basic Security，客户端需要知道密码（如果不是默认的，则需要知道用户名）。你可以通过配置服务器 URI 或通过单独的用户名和密码属性指定用户名和密码，如以下示例所示：

```
spring:
  cloud:
    config:
     uri: https://user:[email protected]
```

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

```
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:[email protected]:8888}
```

如果 Config Server 需要客户端 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`]（#custom-rest-template）提供`ConfigServicePropertySourceLocator`（例如，通过在 Bootstrap 上下文中获取它并将其注入）。

#### [健康指标](#_health_indicator_2)

Config 客户机提供一个 Spring 引导健康指示器，该指示器试图从 Config 服务器加载配置。可以通过设置`health.config.enabled=false`禁用健康指示器。出于性能原因，响应也会被缓存。默认的缓存持续时间为 5 分钟。要更改该值，请设置`health.config.time-to-live`属性（以毫秒为单位）。

#### [提供自定义的 RESTTemplate](#custom-rest-template)

在某些情况下，你可能需要自定义从客户机向配置服务器发出的请求。通常，这样做需要传递特殊的`Authorization`头来验证对服务器的请求。要提供自定义`RestTemplate`:

1. 创建具有`PropertySourceLocator`实现的新配置 Bean，如以下示例所示：

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.*`属性。|
|---|------------------------------------------------------------------------------------------------------------------------------|

1. 在`resources/META-INF`中，创建一个名为`Spring.工厂`的文件，并指定你的自定义配置，如下例所示：

spring.factories

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

#### [Vault](#_vault)

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

```
spring:
  cloud:
    config:
      token: YourVaultToken
```

### [保险库中嵌套的钥匙](#_nested_keys_in_vault)

Vault 支持将密钥嵌套在 Vault 中存储的值中，如以下示例所示：

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

此命令将 JSON 对象写入保险库。要访问 Spring 中的这些值，你将使用传统的 dot（`.`）注释，如下面的示例所示

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

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