Spring Boot 与 Docker
观察 GraphQL 的实际运行

本指南将引导您完成从 Spring Cloud Config Server 启动和获取配置的过程。

你将构建什么

您将设置一个配置服务器,并构建一个客户端,该客户端在启动时加载配置,然后在不重启客户端的情况下刷新配置。

您需要什么

如何完成本指南

与大多数 Spring 入门指南一样,您可以从头开始并完成每个步骤,或者可以跳过您已经熟悉的基本设置步骤。无论哪种方式,您最终都会得到可运行的代码。

从头开始,请继续阅读使用 Spring Initializr 开始

跳过基础知识,请执行以下操作:

完成后,您可以将您的结果与 gs-centralized-configuration/complete 中的代码进行对比。

从 Spring Initializr 开始

您可以使用这个预初始化项目(用于服务应用程序)或这个预初始化项目(用于客户端应用程序),然后点击“生成”以下载一个 ZIP 文件。该项目已配置为适合本教程中的示例。

要手动初始化项目:

  1. 访问 https://start.spring.io。这个服务会拉取应用程序所需的所有依赖项,并为您完成大部分设置工作。

  2. 选择 Gradle 或 Maven 以及您想要使用的语言。本指南假设您选择了 Java。

  3. 点击 Dependencies 并选择 Config Server(用于服务应用程序)或 Config ClientSpring Boot ActuatorSpring Web(用于客户端应用程序)。

  4. 点击 Generate

  5. 下载生成的 ZIP 文件,这是一个根据您的选择配置好的 Web 应用程序归档文件。

如果您的 IDE 集成了 Spring Initializr,您可以直接在 IDE 中完成此过程。

您还可以从 Github 上 fork 该项目,并在您的 IDE 或其他编辑器中打开它。

启动配置服务器

首先,您需要一个配置服务,作为您的Spring应用程序与(通常是)版本控制的配置文件仓库之间的中介。您可以使用Spring Cloud的@EnableConfigServer来启动一个能够与其他应用程序通信的配置服务器。这是一个常规的Spring Boot应用程序,只需添加一个注解即可启用配置服务器。以下代码清单(来自configuration-service/src/main/java/com/example/configurationservice/ConfigurationServiceApplication.java)展示了这样一个应用程序:

/*
 * Copyright 2012-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.configurationservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@EnableConfigServer
@SpringBootApplication
public class ConfigurationServiceApplication {

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

配置服务器需要知道要管理哪个仓库。这里有几个选择,但首先从基于 Git 的文件系统仓库开始。您可以轻松地将配置服务器指向一个 Github 或 GitLab 仓库。在文件系统上,创建一个新目录并在其中运行 git init。然后向 Git 仓库添加一个名为 a-bootiful-client.properties 的文件,并在其中运行 git commit。稍后,您将使用一个 Spring Boot 应用程序连接到配置服务器,该应用程序的 spring.application.name 属性将其标识为 a-bootiful-client。这就是配置服务器知道向特定客户端发送哪组配置的方式。它还会发送 Git 仓库中任何名为 application.propertiesapplication.yml 的文件中的所有值。更具体命名的文件(例如 a-bootiful-client.properties)中的属性键会覆盖 application.propertiesapplication.yml 中的键。

在新创建的 a-bootiful-client.properties 文件中添加一个简单的属性和值(message = Hello world),然后通过 git commit 提交更改。

通过 configuration-service/src/main/resources/application.properties 文件中的 spring.cloud.config.server.git.uri 属性指定 Git 仓库的路径。为了避免在同一台机器上运行此服务器和另一个 Spring Boot 应用程序时出现端口冲突,您还必须指定一个不同的 server.port 值。以下清单(来自 configuration-service/src/main/resources/application.properties)展示了这样的 application.properties 文件:

server.port=8888

spring.cloud.config.server.git.uri=${HOME}/Desktop/config

此示例使用位于 ${HOME}/Desktop/config 的基于文件的 git 仓库。您可以通过创建一个新目录并对其中的属性和 YAML 文件运行 git commit 来轻松创建一个。以下命令集可以完成此操作:

$ cd ~/Desktop/config
$ find .
./.git
...
./application.yml

或者,如果您更改应用程序中的配置文件以指向远程 git 仓库(例如 Github),您也可以使用它。

使用配置客户端从配置服务器读取配置

现在您已经搭建了一个 Config Server,接下来需要启动一个新的 Spring Boot 应用程序,该应用程序使用 Config Server 来加载自身的配置,并且能够在不重启 JVM 的情况下刷新其配置以反映 Config Server 的更改。为此,添加 org.springframework.cloud:spring-cloud-starter-config 依赖项以连接到 Config Server。Spring 会像处理从 application.propertiesapplication.yml 或其他任何 PropertySource 加载的属性文件一样,识别这些配置文件。

配置 Config Client 的属性可以按照 Spring Boot 应用程序的常规方式进行设置。在 configuration-client/src/main/resources/application.properties 中指定客户端的 spring.application.namea-bootiful-client 以及 Config Server 的位置 (spring.config.import)。以下清单展示了该文件的内容:

configuration-client/src/main/resources/application.properties

spring.application.name=a-bootiful-client
spring.config.import=optional:configserver:http://localhost:8888/
management.endpoints.web.exposure.include=*

您还需要启用 /refresh 端点,以演示动态配置更改。上面的代码片段展示了如何通过 management.endpoints.web.exposure.include 属性来实现这一点。

客户端可以通过传统机制(例如 @ConfigurationProperties@Value("${…​}"))或通过 Environment 抽象访问 Config Server 中的任何值。现在,您需要创建一个 Spring MVC REST 控制器来返回已解析的 message 属性的值。有关使用 Spring MVC 和 Spring Boot 构建 REST 服务的更多信息,请参阅构建 RESTful Web 服务指南。

默认情况下,配置值在客户端启动时读取一次,之后不再读取。您可以通过在 MessageRestController 上使用 Spring Cloud Config 的 @RefreshScope 注解,然后触发 refresh 事件,强制 Bean 刷新 其配置(即从 Config Server 拉取更新后的值)。以下代码片段(来自 configuration-client/src/main/java/com/example/configurationclient/ConfigurationClientApplication.java)展示了如何实现这一点:

/*
 * Copyright 2012-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.configurationclient;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class ConfigurationClientApplication {

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

@RefreshScope
@RestController
class MessageRestController {

  @Value("${message:Hello default}")
  private String message;

  @RequestMapping("/message")
  String getMessage() {
    return this.message;
  }
}

测试应用程序

您可以通过先启动配置服务,然后在它运行后再启动客户端来测试端到端的结果。在浏览器中访问客户端应用程序 http://localhost:8080/message。在那里,您应该会在响应中看到 Hello world

将 Git 仓库中的 a-bootiful-client.properties 文件里的 message 键更改为其他值(例如 Hello Spring!)。您可以通过访问 http://localhost:8888/a-bootiful-client/default 来确认配置服务器是否看到了更改。您需要调用 Spring Boot Actuator 的 refresh 端点,以强制客户端刷新并获取新值。Spring Boot 的 Actuator 暴露了应用程序的操作端点(如健康检查和环境信息)。要使用它,您必须将 org.springframework.boot:spring-boot-starter-actuator 添加到客户端应用程序的类路径中。您可以通过向客户端的 refresh 端点发送一个空的 HTTP POST 请求来调用 refresh Actuator 端点:http://localhost:8080/actuator/refresh。然后,您可以通过访问 http://localhost:8080/message 端点来确认它是否生效。

以下命令调用 Actuator 的 refresh 命令:

$ curl -X POST localhost:8080/actuator/refresh -d {} -H "Content-Type: application/json"

我们在客户端应用程序中设置了management.endpoints.web.exposure.include=*,以便于测试(自 Spring Boot 2.0 起,Actuator 端点默认不暴露)。默认情况下,如果您没有设置该标志,仍然可以通过 JMX 访问它们。

总结

恭喜!您刚刚通过首先启动服务然后动态更新其配置,成功使用 Spring 集中了所有服务的配置。

另请参阅

以下指南也可能有所帮助:

本页目录