Spring 实战(第五版)
  • Spring 实战(第 5 版)
  • 第一部分 Spring 基础
  • 第 1 章 Spring 入门
    • 1.1 什么是 Spring?
    • 1.2 初始化 Spring 应用程序
      • 1.2.1 使用 Spring Tool Suite 初始化 Spring 项目
      • 1.2.2 检查 Spring 项目结构
    • 1.3 编写 Spring 应用程序
      • 1.3.1 处理 web 请求
      • 1.3.2 定义视图
      • 1.3.3 测试控制器
      • 1.3.4 构建并运行应用程序
      • 1.3.5 了解 Spring Boot DevTools
      • 1.3.6 回顾
    • 1.4 俯瞰 Spring 风景线
      • 1.4.1 Spring 核心框架
      • 1.4.2 Spring Boot
      • 1.4.3 Spring Data
      • 1.4.4 Spring Security
      • 1.4.5 Spring Integration 和 Spring Batch
      • 1.4.6 Spring Cloud
    • 1.5 小结
  • 第 2 章 开发 Web 应用程序
    • 2.1 展示信息
      • 2.1.1 建立域
      • 2.1.2 创建控制器类
      • 2.1.3 设计视图
    • 2.2 处理表单提交
    • 2.3 验证表单输入
      • 2.3.1 声明验证规则
      • 2.3.2 在表单绑定时执行验证
      • 2.3.3 显示验证错误
    • 2.4 使用视图控制器
    • 2.5 选择视图模板库
      • 2.5.1 缓存模板
    • 2.6 小结
  • 第 3 章 处理数据
    • 3.1 使用 JDBC 读写数据
      • 3.1.1 为域适配持久化
      • 3.1.2 使用 JdbcTemplate
      • 3.1.3 定义模式并预加载数据
      • 3.1.4 插入数据
    • 3.2 使用 Spring Data JPA 持久化数据
      • 3.2.1 添加 Spring Data JPA 到数据库中
      • 3.2.2 注解域作为实体
      • 3.2.3 声明 JPA repository
      • 3.2.4 自定义 JPA repository
    • 3.3 小结
  • 第 4 章 Spring 安全
    • 4.1 启用 Spring Security
    • 4.2 配置 Spring Security
      • 4.2.1 内存用户存储
      • 4.2.2 基于 JDBC 的用户存储
      • 4.2.3 LDAP 支持的用户存储
      • 4.2.4 自定义用户身份验证
    • 4.3 保护 web 请求
      • 4.3.1 保护请求
      • 4.3.2 创建用户登录页面
      • 4.3.3 登出
      • 4.3.4 阻止跨站请求伪造攻击
    • 4.4 了解你的用户
    • 4.5 小结
  • 第 5 章 使用配置属性
    • 5.1 微调自动配置
      • 5.1.1 理解 Spring 环境抽象
      • 5.1.2 配置数据源
      • 5.1.3 配置嵌入式服务器
      • 5.1.4 配置日志
      • 5.1.5 使用特殊的属性值
    • 5.2 创建自己的配置属性
      • 5.2.1 定义配置属性持有者
      • 5.2.2 声明配置属性元数据
    • 5.3 使用 profile 文件进行配置
      • 5.3.1 定义特定 profile 的属性
      • 5.3.2 激活 profile 文件
      • 5.3.3 有条件地使用 profile 文件创建 bean
    • 5.4 小结
  • 第二部分 集成 Spring
  • 第 6 章 创建 REST 服务
    • 6.1 编写 RESTful 控制器
      • 6.1.1 从服务器获取数据
      • 6.1.2 向服务器发送数据
      • 6.1.3 更新服务器上的资源
      • 6.1.4 从服务器删除数据
    • 6.2 启用超媒体
      • 6.2.1 添加超链接
      • 6.2.2 创建资源装配器
      • 6.2.3 嵌套命名关系
    • 6.3 启用以数据为中心的服务
      • 6.3.1 调整资源路径和关系名称
      • 6.3.2 分页和排序
      • 6.3.3 添加用户端点
      • 6.3.4 向 Spring Data 端点添加用户超链接
    • 6.4 小结
  • 第 7 章 调用 REST 服务
    • 7.1 使用 RestTemplate 调用 REST 端点
      • 7.1.1 请求 GET 资源
      • 7.1.2 请求 PUT 资源
      • 7.1.3 请求 DELETE 资源
      • 7.1.4 请求 POST 资源
    • 7.2 使用 Traverson 引导 REST API
    • 7.3 小结
  • 第 8 章 发送异步消息
    • 8.1 使用 JMS 发送消息
      • 8.1.3 接收 JMS 消息
      • 8.1.2 使用 JmsTemplate 发送消息
      • 8.1.1 设置 JMS
    • 8.2 使用 RabbitMQ 和 AMQP
      • 8.2.1 添加 RabbitMQ 到 Spring 中
      • 8.2.2 使用 RabbitTemplate 发送消息
      • 8.2.3 从 RabbitMQ 接收消息
    • 8.3 使用 Kafka 发送消息
      • 8.3.1 在 Spring 中设置 Kafka
      • 8.3.2 使用 KafkaTemplate 发送消息
      • 8.3.3 编写 Kafka 监听器
    • 8.4 小结
  • 第 9 章 集成 Spring
    • 9.1 声明简单的集成流
      • 9.1.1 使用 XML 定义集成流
      • 9.1.2 在 Java 中配置集成流
      • 9.1.3 使用 Spring Integration 的 DSL 配置
    • 9.2 探索 Spring Integration
      • 9.2.1 消息通道
      • 9.2.2 过滤器
      • 9.2.3 转换器
      • 9.2.4 路由
      • 9.2.5 分割器
      • 9.2.6 服务激活器
      • 9.2.7 网关
      • 9.2.8 通道适配器
      • 9.2.9 端点模块
    • 9.3 创建 Email 集成流
    • 9.4 总结
  • 第三部分 响应式 Spring
  • 第 10 章 Reactor 介绍
    • 10.1 理解响应式编程
      • 10.1.1 定义响应式流
    • 10.2 Reactor
      • 10.2.1 图解响应式流
      • 10.2.2 添加 Reactor 依赖
    • 10.3 通用响应式操作实战
      • 10.3.1 创建响应式类型
      • 10.3.2 响应式类型结合
      • 10.3.3 转换和过滤响应式流
      • 10.3.4 对反应类型执行逻辑操作
    • 10.4 总结
  • 第 11 章 开发响应式 API
    • 11.1 使用 Spring WebFlux
      • 11.1.1 Spring WebFlux 介绍
      • 11.1.2 编写响应式 Controller
    • 11.2 定义函数式请求处理程序
    • 11.3 测试响应式 Controller
      • 11.3.1 测试 GET 请求
      • 11.3.2 测试 POST 请求
      • 11.3.3 使用线上服务器进行测试
    • 11.4 响应式消费 REST API
      • 11.4.1 通过 GET 方式获取资源
      • 11.4.2 通过 POST 方式发送资源
      • 11.4.3 删除资源
      • 11.4.4 处理请求错误
      • 11.4.5 请求转换
    • 11.5 保护响应式 web API
      • 11.5.1 配置响应式 Web 安全
      • 11.5.2 配置响应式用户信息服务
    • 11.6 总结
  • 第 12 章 响应式持久化数据
    • 12.1 理解 Spring Data 响应式历程
      • 12.1.1 Spring Data 响应式精髓
      • 12.1.2 在响应式与非响应式之间进行转换
      • 12.1.3 开发响应式库
    • 12.2 使用响应式 Cassandra 库
      • 12.2.1 开启 Spring Data Cassandra
      • 12.2.2 理解 Cassandra 数据模型
      • 12.2.3 Cassandra 持久化实体映射
      • 12.2.4 编写响应式 Cassandra 库
    • 12.3 编写响应式 MongoDB 库
      • 12.3.1 开启Spring Data MongonDB
      • 12.3.2 MongoDB 持久化实体映射
      • 12.3.3 编写响应式 MongoDB 库
    • 12.4 总结
  • 第四部分 云原生 Spring
  • 第 13 章 服务发现
    • 13.1深入思考微服务
    • 13.2 配置服务注册
      • 13.2.1 配置 Eureka
      • 13.2.2 扩展 Eureka
    • 13.3 注册并发现服务
      • 13.3.1 配置 Eureka 客户端属性
      • 13.3.2 消费服务
    • 13.4 总结
  • 第 14 章 配置管理
    • 14.1 共享配置
    • 14.2 运行配置服务器
      • 14.2.1 启动配置服务器
      • 14.2.2 填写配置库
    • 14.3 消费共享的配置
    • 14.4 服务应用程序和特定配置文件的属性
      • 14.4.1 服务特定应用程序的属性
      • 14.4.2 服务配置文件属性
    • 14.5 为配置的属性加密
      • 14.5.1 在 Git 中加密属性
      • 14.5.2 在 Vault 中存储密码
    • 14.6 远程刷新配置属性
      • 14.6.1 手动刷新配置属性
      • 14.6.2 自动刷新配置属性
    • 14.7 总结
  • 第 15 章 处理失败和时延
    • 15.1 了解断路器
    • 15.2 定义断路器
      • 15.2.1 缓解时延
      • 15.2.2 管理断路器阈值
    • 15.3 管理失败事件
      • 15.3.1 介绍 Hystrix 面板
      • 15.3.2 了解 Hystrix 线程池
    • 15.4 聚合多个 Hystrix 流
    • 15.5 总结
  • 第五部分 部署Spring
  • 第 16 章 使用 SpringBoot Actuator
    • 16.1 介绍 Actuator
      • 16.1.1 配置 Actuator 基本路径
      • 16.1.2 启用和禁用 Actuator 端点
    • 16.2 使用 Actuator 端点
      • 16.2.1 获取重要的应用程序信息
      • 16.2.2 查看配置详细信息
      • 16.2.3 查看应用程序活动
      • 16.2.4 利用运行时指标
    • 16.3 自定义 Actuator
      • 16.3.1 向 /info 端点提供信息
      • 16.3.2 自定义健康指标
      • 16.3.3 注册自定义指标
      • 16.3.4 创建自定义端点
    • 16.4 保护 Actuator
    • 16.5 总结
  • 第 17 章 管理 Spring
    • 17.1 使用 SpringBoot Admin
      • 17.1.1 创建 Admin 服务端
      • 17.1.2 注册 Admin 客户端
    • 17.2 深入 Admin 服务端
      • 17.2.1 查看普通应用程序运行状况和信息
      • 17.2.2 观察关键指标
      • 17.2.3 检查环境属性
      • 17.2.4 查看并设置 log 级别
      • 17.2.5 监控线程
      • 17.2.6 追踪 HTTP 请求
    • 17.3 保护 Admin 服务端
      • 17.3.1 在 Admin 服务端中启用登录
      • 17.3.2 使用 Actuator 进行认证
    • 17.4 总结
  • 第 18 章 使用 JMX 监控 Spring
    • 18.1 使用 Actuator MBean
    • 18.2 创建自己的 MBean
    • 18.3 发送通知
    • 18.4 总结
  • 第 19 章 部署 Spring
    • 19.1 权衡部署选项
    • 19.2 构建并部署 WAR 文件
    • 19.3 将 JAR 文件推送到 Cloud Foundry
    • 19.4 在 Docker 容器中运行 SpringBoot
    • 19.5 终章
    • 19.6 总结
由 GitBook 提供支持
在本页

这有帮助吗?

  1. 第 14 章 配置管理
  2. 14.6 远程刷新配置属性

14.6.2 自动刷新配置属性

上一页14.6.1 手动刷新配置属性下一页14.7 总结

最后更新于3年前

这有帮助吗?

除了手动刷新应用程序配置以外,通过另一个名为 Spring Cloud Bus 的 Spring Cloud 项目,Config Server 可以自动通知所有客户端进行配置更改。图 14.7 展示了自动刷新配置的工作原理。

图 14.7 所示的属性刷新过程可以概括如下:

  • 在配置 Git 存储库上创建一个 webhook,用来通知 Config Server 任何 Git 存储库的更改(如:push)。Webhooks 支持很多 Git 实现,包括 GitHub、GitLab、Bitbucket、Gogs。

  • Config Server 通过广播消息来响应 webhook POST 请求,通过消息代理(如 RabbitMQ 或 Kafka)广播更改。

  • 订阅通知的各个 Config Server 客户端应用程序,响应通知消息,使用来自 Config Server 的属性值刷新应用配置。

其效果是,所有使用 Config Server 的客户端应用程序都将始终具有最新配置,配置更改被推送到后端 Git 存储库后,各应用程序紧跟着进行刷新。

使用自动属性刷新时,需要几个部分同步工作。让我们整体看一下您将要进行的更改,以有一个更直观的理解:

  • 您将需要一个消息代理来处理 Config Server 及其客户端之间的消息传递。比如选择 RabbitMQ 或 Kafka。

  • 需要在后端 Git 存储库中创建一个 webhook 来通知 Config Server 相关修改。

  • 需要使用 Config Server 监视器依赖项(它提供了接口,以处理来自 Git 存储库的调用请求),启用 Config Server 和 RabbitMQ 或 Kafka Spring Cloud Stream 依赖关系(用于向消息代理发布属性更改消息)。

  • 除非消息代理以默认设置在本地运行,否则需要在 Config Server 及其客户端中,配置连接消息代理的详细信息。

  • 每个 Config Server 客户端应用程序都需要 Spring Cloud Bus 依赖。

我将假设必备的消息代理(RabbitMQ 或 Kafka 等等)已经运行,并准备传递属性更改消息了。您要开始对配置进行修改,以触发 webhook 更新请求。

创建 WEBHOOK

许多 Git 服务器实现都支持创建 webhook。一旦对 Git 存储库进行更改(包括推送),就可以使用 webhook 来通知应用程序。 设置 webhook 的细节,会因为 Git 服务器实现不同而不同。我们很难都详细的讲到。下面通过在 Gogs 上配置 webhook 以让您了解整个过程。

我选择 Gogs 是因为它很容易在本地运行,并且可以通过 webhook 发送 POST 请求到到本地应用程序(GitHub 很难做到这一点)。也因为对 Gogs 设置 webhook 的过程,与在 GitHub 进行设置的过程基本一样。清楚了 Gogs 的设置过程,您就间接地了解了为 GitHub 设置 webhook 的过程。

首先,在 web 浏览器中访问配置存储库,并单击设置链接,如图 14.8 所示(设置链接的位置在 GitHub 中略有不同,但看起来比较类似。)

这将带您进入存储库的设置页面,左侧是分类设置菜单。从菜单中选择 Webhooks 将显示类似于图 14.9 的页面。

在 webhooks 设置页面中,单击 add webhook 按钮。在 Gogs,这将打开一个下拉列表,用于新建不同类型的 webhook。选择 Gogs 选项,如图 14.9 所示。然后,您将看到一个表单用来来创建一个新的webhook,如图 14.10 所示:

新建 webhook 表单有几个字段,最重要的两个字段是 Payload URL 和 Content Type 。很快您就能使 Config Server 来处理 webhook 的 POST 请求。那时,Config Server 能够处理对 /monitor 路径的请求。因此,Payload URL 字段应设置为指向 Config Server 的 /monitor 接口的 URL。因为我在 Docker 容器中运行 Gogs ,我在 图14.10 中给出的 URL 是 http://host.docker.internal:8888/monitor,其主机名为 host.docker.internal。此主机名使 Gogs 服务器能够访问到在主机上运行的 Config Server。

我还将 Content Type 字段设置为 application/json。这很重要,因为 Config Server 的 /monitor 接口不支持 application/x-www-formurlencoded 等其他选项。

如果设置了 Secret 字段,将在 webhook POST 请求中包含一个名为 X-Gogs-Signature(如果是 GitHub,则为 X-Hub-Signature)的请求头,值为 HMAC-SHA256 数字摘要(如果是 GitHub,则为 HMAC-SHA1 摘要)。现在,Config Server 的 /monitor 接口还无法识别这个签名头信息,因此您可以将此字段留空。

最后,您只关心将配置推送到配置存储库,并且希望 webhook 处于激活状态,所以您要确保事件单选按钮 Just the Push Event 和 Active 复选框被选中。单击 Add Webhook 按钮,webhook 将被创建。每当向存储库推送进行配置推送时,webhook 就会向 Config Server 发送 POST 请求。

现在您必须在 Config Server 中启用 /monitor 接口来处理这些请求。

在 Config Server 中处理 WEBHOOK 更新

在 Config Server 中启用 /monitor 接口,只需在工程中添加 spring-cloud-config-monitor 依赖。在 pom.xml 文件中添加以下内容:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-config-monitor</artifactId>
</dependency>

有了这个依赖,自动配置将启动 /monitor 接口。但是这还不够,除非 Config Sever 也有一种广播更改的能力。您还需要为 Spring 添加另一个依赖 Spring Cloud Stream。

Spring Cloud Stream 是 Spring Cloud 的又一个组件;它使各服务通过某种底层机制(比如:RabbitMQ 或 Kafka)进行通信。 这些服务编写的时候,并不知道他们是如何被使用的。他们从流中接收数据,然后进行处理。处理结束将处理结果返回到流,以供下游服务处理。或将接收的数据和处理结果都返回到流中。

/monitor 接口使用 Spring Cloud Stream 发送通知消息到相关的 Config Server 客户端。为了避免硬编码任何特定的消息实现,monitor 充当 Spring Cloud Stream 发布消息入口,并让底层实现来具体处理发送消息的细节。

如果您使用的是 RabbitMQ,则需要在 Config Server 中包含 Spring Cloud Stream RabbitMQ 依赖:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

如果您更喜欢 Kafka,就需要 Spring Cloud Stream Kafka 依赖项:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

有了这些依赖项,Config Server 就差不多可以参与自动刷新配置属性了。事实上,如果 RabbitMQ 或 Kafka 的代理,使用默认配置运行在本地, Config Server 现在就可以很好的运行。但是如果代理运行在其他主机上,并且使用了某个非默认端口,或者您已经更改了访问代理的凭据,则需要在 Config Server 中设置一些配置属性。

使用 RabbitMQ 时,可以在 application.yml 中设置以下属性替代默认值:

spring:
  kafka:
    bootstrap-servers:
    - kafka.tacocloud.com:9092
    - kafka.tacocloud.com:9093
    - kafka.tacocloud.com:9094

您在第 8 章中看到过这些属性,我们在第 8 章中讨论了 Kafka 消息服务。实际上,为自动刷新配置使用 RabbitMQ 或 Kafka 的方式,和在其他用途中使用它们的方式是一样的。

创建 GOGS 通知提取程序

每个 Git 实现在处理 webhook POST 请求时,都有自己的特性。所以 /monitor 接口要能够理解 webhook POST 请求时的不同数据格式。在 /monitor 接口底层是一组组件,它检查 POST 请求,尝试确定请求来自哪种 Git 服务器,并将请求数据映射到一种公共的数据类型中,以发送给每个客户端。

Config Server 提供了对几种流行 Git 实现的支持,比如 GitHub、GitLab 和 Bitbucket。如果您用的是这些 Git 实现,就不需要任何特殊处理。当我写这篇文章时,Gogs 还没有正式发布。因此,如果您使用 Gogs 作为 Git 实现,您需要一个特定于 Gogs 的通知提取程序。

下一个清单显示了为 Taco Cloud 实现的 Gogs 通知提取器。

程序清单 14.1 Gogs 通知提取器的实现
package tacos.gogs;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.cloud.config.monitor.PropertyPathNotification;
import org.springframework.cloud.config.monitor.PropertyPathNotificationExtractor;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;

@Component
@Order(Ordered.LOWEST_PRECEDENCE - 300)
public class GogsPropertyPathNotificationExtractor
    implements PropertyPathNotificationExtractor {

  @Override
  public PropertyPathNotification extract(
      MultiValueMap<String, String> headers,
      Map<String, Object> request) {
    if ("push".equals(headers.getFirst("X-Gogs-Event"))) {
      if (request.get("commits") instanceof Collection) {
        Set<String> paths = new HashSet<>();
        @SuppressWarnings("unchecked")
        Collection<Map<String, Object>> commits =
            (Collection<Map<String, Object>>) request.get("commits");
            for (Map<String, Object> commit : commits) {
                addAllPaths(paths, commit, "added");
                addAllPaths(paths, commit, "removed");
                addAllPaths(paths, commit, "modified");
            }
            if (!paths.isEmpty()) {
                return new PropertyPathNotification(
                    paths.toArray(new String[0]));
            }
        }
    }
    return null;
  }

  private void addAllPaths(Set<String> paths,
                Map<String, Object> commit,
                String name) {
    @SuppressWarnings("unchecked")
    Collection<String> files = (Collection<String>) commit.get(name);
    if (files != null) {
        paths.addAll(files);
    }
  }
}

GogsPropertyPathNotificationExtractor 的实现细节和我们要讨论的内容不是太相关。一旦 Spring Cloud Config Server 内置支持了 Gogs 时,就更不需要关注了。因此,这里就不多说了。如果有兴趣,可以自己看一下。

在 Config Server 客户端中启用自动刷新

在 Config Server 客户端中启用自动属性刷新非常简单,只需要一个依赖项:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

这会将 AMQP(例如,RabbitMQ) Spring Cloud Bus 添加到项目中。如果您使用的是 Kafka,则应改用以下依赖项:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bus-kafka</artifactId>
</dependency>

项目中有了 Spring Cloud Bus 以后,应用程序在启动时自动配置将会触发,会自动绑定到本地运行的 RabbitMQ 或 Kafka 群集的 Broker 上。如果您的 RabbitMQ 或 Kafka 在其他地方运行,那么您将需要在 Config Server 的客户端进行适当的配置,就像在 Config Server 上配置时那样。

现在,Config Server 及其客户端都配置为自动刷新了。启动所有工程,通过修改 application.yml (任何修改)让它运转起来。当您把修改推到 Git 存储库时,您将立即在客户端应用程序中发现修改生效。