HashiCorp Consul(哈希 icorp 的 Consul)
HashiCorp Consul(https://www.consul.io/)是一个服务网络平台,旨在管理不同环境(包括本地部署、多云和各种运行时)之间的安全连接。它充当服务发现、安全通信和网络自动化的中央控制平面。
以下是一些 Consul 的应用场景:
- 微服务架构:轻松连接和管理微服务,支持动态服务发现和健康检查。
- 多云和混合部署:确保不同云服务提供商与本地基础设施之间的服务连接一致。
- API 网关和服务网格:实现安全的服务间通信,具备自动 TLS 加密和基于身份的授权等功能。
- 网络自动化:根据服务变更自动配置和更新网络基础设施。
Consul 包含以下功能(以及其他功能):
- 服务发现:通过 DNS、HTTP 或 gRPC 接口注册和查找服务。
- 健康检查:监控服务状态并自动注销不健康的实例。
- 安全通信:启用服务间加密,使用相互 TLS(mTLS)和基于身份的授权。
- 键值存储:在 Consul 中安全地存储配置和机密信息。
- 多数据中心支持:可以在多个数据中心或区域之间无缝扩展 Consul。
- 服务网格集成:与现有的服务网格(如 Linkerd 或 Istio)进行整合。
- API 网关:在 Consul 服务网格中管理服务的流量和访问控制。
- 网络自动化:根据服务变更自动化网络基础设施的配置。
使用 Consul 的好处包括
- 简化服务管理:集中管理服务发现、健康检查和安全。
- 提高灵活性:借助多平台支持加快服务的部署和扩展。
- 提升运营效率:自动化任务,获得对服务的全面视图。
- 加强安全性:实施最小权限访问并启用安全通信。
使用 HashiCorp Consul 工具
在本节中,我们将使用 Docker 启动 Consul 服务器和 Consul 客户端。Consul 需要一种服务器-客户端架构,以提供分布式共识、高可用性、安全性和高效管理等功能,这些功能仅靠客户端无法实现。这种架构确保了在各种场景下服务发现和网络的可靠性、可扩展性和安全性。
要启动 Consul 服务器,请运行以下命令:
docker run \
-d \
-p 8500:8500 \
-p 8600:8600/udp \
--rm \
--name=consul-server \
consul:1.15.4 agent -server -ui -node=server-1 -bootstrap-expect=1 -client=0.0.0.0
注意:撰写本文时,Consul 的版本是 1.15.4。您可以访问 Docker Hub 查看最新版本:
https://hub.docker.com/_/consul。
接下来,让我们找出客户需要用来连接服务器的地址。请执行以下命令:
docker exec consul-server consul members
此命令的输出是默认的 Docker IP 地址(通常是 172.17.0.2)。接下来,您可以启动客户端并使用这个 IP 地址:
docker run \
--name=consul-client --rm -d \
consul:1.15.4 agent -node=client-1 -retry-join=172.17.0.2
由于我们将使用 Consul 作为外部配置机制,因此需要添加一些键。您可以通过 Consul 的 REST API 或安装 Consul CLI 工具来与其交互 (
https://developer.hashicorp.com/consul/docs/install)。
以下命令会添加所需的键值对:
curl -X PUT -d 'admin' http://localhost:8500/v1/kv/config/users-service/db/username
curl -X PUT -d 'mysecretpassword' http://localhost:8500/v1/kv/config/users-service/db/password
需要特别注意的是,我们采用了一种非常特定的方式来添加这些键值对。我们遵循 Spring Cloud Consul 的约定,这要求使用这种语法:
config//
config/,/
因此,在这种情况下,我们将 users-service 作为应用程序名称(spring.application.name),db.username 和 db.password 作为属性。这些属性用于我们的数据库。
此外,请添加以下属性(我们在此使用 consul CLI):
consul kv put config/users-service/user/reportFormat PDF
consul kv put config/users-service/user/emailSubject 'Welcome to the Users Service!'
consul kv put config/users-service/user/emailFrom 'users@email.com'
consul kv put config/users-service/user/emailTemplate '
Thanks for choosing Users Service
We have a REST API that you can use to integrate with your Apps.
Thanks from the Users App team.'
此外,您可以通过在浏览器中输入 http://localhost:8500 来使用图 13-2 所示的 Web 界面。
图 13-2 HashiCorp Consul 网页用户界面 (http://localhost:8500)
如果你查看键值部分,你应该能看到如图 13-3 所示的 db.* 和 user.* 属性。
图 13-3 Consul 键值部分(config/users-service/user 属性)
现在,让我们来回顾一下 Spring Cloud Consul 技术及其如何帮助我们使用 HashiCorp Consul。
Spring Cloud Consul
Spring Cloud Consul 是一个库,能够无缝地将 Spring Boot 应用程序与 HashiCorp Consul 集成。它利用 Consul 的功能,简化了基于 Spring 构建的微服务架构中的服务发现、通信和配置管理。
Spring Cloud Consul 的一些主要特点包括
- 简化的服务发现方式:
- 使用 Consul 自动注册和发现 Spring Boot 应用。
- 通过使用注释,可以在无需手动配置的情况下集成服务发现功能。
- 支持 Spring Cloud LoadBalancer 实现智能路由,并通过 Ribbon 实现客户端负载均衡。
- 与 Spring Cloud Gateway 集成,实现动态 API 网关路由。
- 强大的配置管理系统:
- 利用 Consul 的键值存储实现集中配置管理。
- 使用 Spring 环境来访问存储在 Consul 中的配置值。
- 动态更新所有服务的配置,无需单独进行重新部署。
- 安全服务通信
- 通过利用 Consul 的内置安全功能来启用强大的相互 TLS(mTLS)加密。
- 强制实施基于身份的授权,以确保安全的访问控制。
- 分布式控制总线
- 利用 Consul 的事件在微服务环境中触发相应的操作。
- 发送和接收事件以便于协调和通知。
- 与其他 Spring Cloud 项目的整合:
- 可以与其他 Spring Cloud 项目无缝集成,例如 Spring Cloud Netflix,以实现 Hystrix 弹性等高级功能。
使用 Spring Cloud Consul 的优势包括:
- 减少开发时间:通过注解和自动配置,简化了服务发现和配置管理的过程。
- 提升开发者体验:提供了一种熟悉的 Spring 方式来使用 Consul,从而降低学习曲线。
- 提升的可靠性和可扩展性:利用 Consul 的高可用性和多数据中心支持,构建强大的微服务。
- 提高安全性:在您的微服务架构中强制实施安全通信和授权。
本质上,Spring Cloud Consul 连接了 Spring Boot 应用程序与 Consul,使开发者能够轻松构建出弹性、可扩展且安全的微服务。
在用户应用中使用 Spring Cloud Consul
在本节中,我们将为用户应用添加 Spring Cloud Consul,并回顾服务发现功能和外部配置。使用 Consul 和 Spring Cloud Consul 等工具的外部配置为微服务架构带来了显著优势。它提高了灵活性、增强了安全性、改善了可维护性,并简化了扩展,从而促进了微服务生态系统的整体成功。
让我们从用户应用程序开始。本章的源代码位于 13-cloud/users 文件夹中。如果您想使用 Spring Initializr(https://start.spring.io)从头开始,请将 Group 字段设置为 com.apress,将 Artifact 和 Name 字段设置为 users,并将 JPA、PostgreSQL、Web、Validation、Actuator、Consul Configuration、Consul Discovery 和 Lombok 作为依赖项添加。其他所有设置保持默认。然后,生成并下载项目,解压缩后导入到您喜欢的 IDE 中。
让我们先打开 build.gradle 文件,参见列表 13-1。
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.2'
id 'io.spring.dependency-management' version '1.1.4'
id 'org.hibernate.orm' version '6.1.7.Final'
id 'org.graalvm.buildtools.native' version '0.9.20'
}
group = 'com.apress'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
ext {
set('springCloudVersion', "2023.0.0")
}
repositories {
mavenCentral()
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Consult
implementation 'org.springframework.cloud:spring-cloud-starter-consul-config'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery'
runtimeOnly 'org.postgresql:postgresql'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
// Web
implementation 'org.webjars:bootstrap:5.2.3'
// Test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
hibernate {
enhancement {
lazyInitialization true
dirtyTracking true
associationManagement true
}
}
列表 13-1 的 build.gradle 文件
列表 13-1 显示我们正在使用 Maven Bom(构件清单),这使我们能够获取所需的 spring-cloud-dependencies,其中包括
spring-cloud-starter-consul-config(用于外部配置)和
spring-cloud-starter-consul-discovery(用于服务发现)。
接下来,创建或打开 UserProperties 类。请参阅第 13-2 号列表。
package com.apress.users.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "user")
public class UserProperties {
private String reportFormat;
private String emailSubject;
private String emailFrom;
private String emailTemplate;
}
列表 13-2 源代码:
src/main/java/com/apress/users/config/UsersProperties.java
列表 13-2 显示,我们将 UserProperties 类标记为@ConfigurationProperties,这意味着该值将在启动时进行绑定。这些值存储在外部存储中,在本例中是 Consul 服务器。因此,我们需要创建例如
config/users-service/user/reportFormat 这个键及其值 PDF。
接下来,打开或创建 application.yaml 文件。请参阅列表 13-3。
spring:
application:
name: users-service
config:
import: consul://
datasource:
url: jdbc:postgresql://localhost:5432/users_db?sslmode=disable
username: ${db.username}
password: ${db.password}
jpa:
generate-ddl: true
show-sql: true
hibernate:
ddl-auto: update
info:
developer:
name: Felipe
email: felipe@email.com
api:
version: 1.0
management:
endpoints:
web:
exposure:
include: health,info,event-config,shutdown,configprops,beans
endpoint:
configprops:
show-values: always
health:
show-details: always
status:
order: events-down, fatal, down, out-of-service, unknown, up
shutdown:
enabled: true
info:
env:
enabled: true
server:
port: ${PORT:8080}
列表 13-3 源自
main/resources/application.yaml 文件。
应用程序的 YAML 文件包含以下内容:
- 这个属性是必需的,因为配置基于命名约定,因此必须在此处设置名称。在这种情况下,我们将名称设置为 users-service。
- spring.config.import:该属性告诉 Spring Boot 部分配置位于 Consul 服务器,因此其值设置为 consul://。
- spring.datasource.username 和 spring.datasource.password:这两个属性分别对应 ${db.username} 和 ${db.password}。它们的值将分别从 config/users-service/db/username 和 config/users-service/db/password 中获取。
- 默认情况下,/configpros 端点会隐藏所有属性的值,但我们将此键设置为始终显示属性,因为我们将要展示一个非常酷的配置属性功能。
我们之前已经介绍了列表 13-3 中的其他属性,因此在这里不再重复。
使用 Spring Consul 启动用户应用程序
要运行用户应用程序,我们需要先启动 PostgreSQL 数据库。请执行以下命令来启动 PostgreSQL 数据库:
docker run --name postgres --rm \
-p 5432:5432 \
--platform linux/amd64 \
-e POSTGRES_PASSWORD=mysecretpassword \
-e POSTGRES_USER=admin \
-e POSTGRES_DB=users_db \
-d postgres
数据库启动并运行后,您可以运行应用程序。将端口设置为 8091,可以通过您的 IDE(每个 IDE 都有设置环境变量的方式)或执行以下命令来完成:
PORT=8091 ./gradlew bootRun
一切应该正常运行!如果你查看 Consul UI 的服务部分(
http://localhost:8500/ui/dc1/services),你应该能看到列出的 users-service(下方显示“1 个实例”)。请参见图 13-4。
图 13-4 Consul UI 服务部分 (
http://localhost:8500/ui/dc1/services)
那么,发生了什么呢?因为我们添加了
spring-cloud-starter-consul-discovery 依赖,Spring Boot 和 Spring Cloud Consul 的自动配置会将这个服务自动注册到 HashiCorp Consul,从而使其他服务能够发现它。而且由于我们添加了
spring-cloud-starter-consul-config 依赖,并将 spring.config.import 键设置为 consul://,它会根据命名约定从 Consul Config 存储中获取所有属性,即 config/users-service/* 属性。因此,当它看到 db.username 时,值会从
consul://config/users-service/db/username 中获取;而当它看到 user.reportFormat(来自 UserProperties 类)时,值会从
consul://config/users-service/user/reportFormat 中获取。非常不错,对吧?
现在回到浏览器,如果你点击用户服务,你会看到类似于图 13-5 的内容。
图 13-5 Consul 用户界面显示 users-service-8091
Consul 通过 spring-boot-actuator 的端点(/actuator/health)来检查服务是否正常运行。
那么,如果你有多个用户应用实例,会发生什么呢?你可以打开另一个终端,使用以下命令来运行另一个实例:
PORT=8092 ./gradlew bootRun
如果你再次查看 Consul UI 的服务部分,你会看到它更新为如图 13-6 所示,用户服务下显示“2 个实例”。点击用户服务,你将看到列出的两个服务,如图 13-7 所示。
你在审查用户属性吗?
接下来,让我们通过 actuator 来查看我们的 UserProperties 类。请将浏览器指向
http://localhost:8091/actuator/configprops 这个端点。如图 13-8 所示,您应该能看到我们之前输入的值(在 Consul 中)。
图 13-8
http://localhost:8091/actuator/configprops
如果您需要在应用程序运行时更改任何属性,您需要重新启动应用程序。不过,使用 Spring Boot 和 Spring Cloud Consul 组合的一个优点是,Spring Boot 提供了 @RefreshScope 注解,允许您更改属性的值,Spring Boot 会自动重新创建带有此标记的 bean,并更新为新值。因此,例如,假设您有如下内容:
@Configuration
public class UserConfigurationExample {
@Value("${message}")
private String message;
...
}
此配置会查找
config/users-service/message,即使您在 Consul 中进行了更改,它也不会改变。这是因为它在应用程序启动时就已设置并使用。因此,如果您需要更改此行为并使用新的值集,则需要使用 @RefreshScope 注解:
@RefreshScope
@Configuration
public class UserConfigurationExample {
@Value("${message}")
private String message;
...
}
使用 YAML 格式代替键值对作为配置方式
如果你再次查看 application.yaml 文件(见列表 13-3),你可能会想知道是否可以在 Consul 中将所有内容格式化为 YAML。答案是可以的,你可以添加整个 YAML 块,而不是键值对。要启用此功能,你需要在 application.yaml 文件中将格式属性设置为 YAML:
spring:
cloud:
config:
format: YAML
然后你需要添加一个数据键并设置所有的 YAML 配置。因此,你需要在 config/users-service 中添加 data 键,并将以下内容作为其值:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/users_db?sslmode=disable
username: admin
password: mysecretpassword
jpa:
generate-ddl: true
show-sql: true
hibernate:
ddl-auto: update
info:
developer:
name: Felipe
email: felipe@email.com
api:
version: 1.0
management:
endpoints:
web:
exposure:
include: health,info,event-config,shutdown,configprops,beans
endpoint:
configprops:
show-values: always
health:
show-details: always
status:
order: events-down, fatal, down, out-of-service, unknown, up
shutdown:
enabled: true
info:
env:
enabled: true
user:
reportFormat: PDF
emailSubject: 'Welcome to the User Services'
emailFrom: 'user@email.com'
emailTemplate: 'Thanks for choosing Users Service'
现在我们正在将数据库的用户名和密码添加到 yaml(config/users-service/data 值)以及 user.*属性中。请参见图 13-9。
图 13-9 Consul UI 的键值部分显示了 config/users-service/data 键
您的 application.yaml 文件将包含列表 13-4 中所示的内容。
spring:
application:
name: users-service
config:
import: consul://
cloud:
config:
format: YAML
server:
port: ${PORT:8080}
列表 13-4 源文件:
src/main/resources/application.yaml
正如你所看到的,使用最小配置后,一切都已外部化。当然,你可以使用 Spring Profiles(例如测试、开发、生产等)进行调整,使其更加灵活可配置。
在我的复古应用程序中使用 Spring Cloud Consul
现在我们要为我的复古应用程序添加 Spring Cloud Consul 功能。源代码位于 13-cloud/myretro 文件夹中。我们将重用第 11 章的 Spring Boot Actuator 代码,并进行一些修改。如果您想从头开始使用 Spring Initializr(https://start.spring.io),请将 Group 字段设置为 com.apress,将 Artifact 和 Name 字段设置为 myretro,并添加 JPA、H2、Web、Validation、Actuator、Consul Configuration、Consul Discovery、OpenFeign 和 Lombok 作为依赖项。其他设置保持默认。然后,生成并下载项目,解压缩后导入到您喜欢的 IDE 中。
首先打开 build.gradle 文件,参见列表 13-5。
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.2'
id 'io.spring.dependency-management' version '1.1.4'
id 'org.hibernate.orm' version '6.1.7.Final'
id 'org.graalvm.buildtools.native' version '0.9.20'
}
group = 'com.apress'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "2023.0.0")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Consul
implementation 'org.springframework.cloud:spring-cloud-starter-consul-config'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery'
// OpenFeign
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
// Kubernetes
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-all'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
tasks.named('test') {
useJUnitPlatform()
}
列表 13-5 的 build.gradle 文件
列表 13-5 显示,我们在 build.gradle 中不仅添加了 spring-cloud-start-consul 依赖项,还添加了
spring-cloud-starter-openfeign 和
spring-cloud-starter-kubernetes-client-all 依赖项。我们将在本章最后一节讨论 Kubernetes 客户端,这将帮助我们理解为什么需要在这里包含它。
如果你还记得,My Retro App 有一种与 Users App 进行通信的方式。在第 12 章中,我们使用了 @HttpExchange 和 @GetExchange 注解,这些注解简化了与其他服务 API 连接的方式。这次我们将采用不同的方法。
在我的复古应用程序中使用 OpenFeign
Spring Cloud OpenFeign 是一个库,它通过声明性地定义带有 Spring MVC 注解的客户端接口,简化了对 RESTful 网络服务的调用。它会根据这些接口自动生成客户端,并处理诸如以下任务:
- 基于如@GetMapping 和@PostMapping 注解的 HTTP 请求映射
- 使用 Spring 的 HttpMessageConverters 进行参数的解码和编码
- Feign 拦截器集成用于自定义请求和响应处理
- Hystrix 故障容忍机制用于增强服务调用的弹性
以下是 Spring Cloud OpenFeign 的主要特点:
- 基于声明式接口的客户端:编写接口,而非底层 HTTP 代码,以实现更清晰、更简洁的方式。
- Spring MVC 注解:利用熟悉的 Spring MVC 注解,提供直观的语法和便捷的集成。
- 默认的编码器和解码器支持:使用 Spring 的默认消息转换器,实现数据处理的无缝对接。
- 支持 Feign 拦截器:集成自定义拦截器以实现额外的处理和日志记录。
- Hystrix 集成:自动为可靠的服务调用启用 Hystrix 故障容错功能。
- 负载均衡支持:与 Spring Cloud LoadBalancer 集成,提供智能的服务发现和路由功能。
- 服务发现集成:可以与多种服务发现工具(如 Eureka 和 Consul)协同工作。
- OAuth2 支持:简化与 OAuth2 保护服务的安全通信方式。
- Micrometer 支持:通过 Micrometer 监控和收集 Feign 客户端的指标。
- Spring Data 支持:可以直接使用 Spring Data 仓库与 Feign 客户端,方便地访问数据。
- Spring @RefreshScope 支持:在应用程序运行时动态更新 Feign 客户端的配置。
Spring Cloud OpenFeign 的一些优势包括
- 减少开发时间:声明式方法和注解使客户端开发变得更加简单。
- 提高可维护性:代码更简洁,关注点分离更加清晰。
- 提高可重用性:接口有助于代码的重用和更便捷的共享。
- 自动化 Hystrix 弹性:内置的故障容错机制,确保服务通信的可靠性。
- 无缝的 Spring 集成:充分利用熟悉的 Spring 概念和工具。
Spring Cloud OpenFeign 帮助开发者构建具有弹性、可维护性和可扩展性的微服务架构的 RESTful 客户端。如果您想了解更多信息,请访问
https://spring.io/projects/spring-cloud-openfeign。
我们也将使用 Consul 来支持 My Retro App,并且需要一种连接到 Users App 的方式。为此,我们将利用 OpenFeign 和 Consul 提供的服务发现和负载均衡功能。请注意,我们有两个正在运行的 Users Service App 实例;My Retro App 将同时连接这两个实例。
接下来,打开或创建 UserClient 接口。请参阅第 13-6 号列表。
package com.apress.myretro.client;
import com.apress.myretro.client.model.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "users-service")
public interface UserClient {
@GetMapping("/users")
ResponseEntity> getAllUsers();
@GetMapping("/users/{email}")
ResponseEntity getById(@PathVariable String email);
}
示例 13-6
src/main/java/com/apress/myretro/client/UserClient.java
让我们来回顾一下这些注释:
- @FeignClient:这个注解用于传递服务名称,在这里是 users-service,这是在 Consul 中注册的服务。
- 你已经了解这个注解,正如你所看到的,我们在 UsersController 中定义了与之前相同的内容,这里有两个方法,一个用于获取所有用户,另一个用于通过电子邮件查找用户。
接下来,打开或创建 RetroBoardConfig 类。请参阅第 13-7 号列表。
package com.apress.myretro.config;
import com.apress.myretro.board.Card;
import com.apress.myretro.board.CardType;
import com.apress.myretro.board.RetroBoard;
import com.apress.myretro.service.RetroBoardAndCardService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
@EnableFeignClients(basePackages = "com.apress.myretro.client")
@Configuration
public class RetroBoardConfig {
@Bean
CommandLineRunner init(RetroBoardAndCardService service){
return args -> {
//... some code here
};
}
}
列表 13-7 源代码:
src/main/java/com/apress/myretro/config/RetroBoardConfig.java
列表 13-7 显示,RetroBoardConfig 类有一个新的注解:@EnableFeignClients(basePackages = "com.apress.myretro.client")。这是一种告诉自动配置所有客户端位置的方法。尽管只有一个客户端,这就是设置它的方式,或者你可以使用 clients 参数,将实际类 UserClient.class 作为值添加。
接下来,我们需要配置 UserClient 接口,以便 My Retro App 能够与 Users App 进行通信。请打开或创建 RetroBoardAndCardService 类,详见列表 13-8。
package com.apress.myretro.service;
import com.apress.myretro.board.RetroBoard;
import com.apress.myretro.client.UserClient;
import com.apress.myretro.events.RetroBoardEvent;
import com.apress.myretro.events.RetroBoardEventAction;
import com.apress.myretro.exceptions.RetroBoardNotFoundException;
import com.apress.myretro.persistence.RetroBoardRepository;
import io.micrometer.core.instrument.Counter;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.UUID;
@AllArgsConstructor
@Service
public class RetroBoardAndCardService {
private RetroBoardRepository retroBoardRepository;
private ApplicationEventPublisher eventPublisher;
private Counter retroBoardCounter;
private UserClient userClient;
// more code here...
// External Call
public void getAllUsers(){
userClient.getAllUsers().getBody().forEach(System.out::println);
}
}
列表 13-8 源代码:
src/main/java/com/apress/myretro/service/RetroBoardAndCardService.java
在列表 13-8 中,重要的一点是我们注入了 UserClient 接口,并且仅在 getAllUsers 方法中使用它(我们只是打印这些值)。
接下来,打开或创建 RetroBoardController 类。这是一个用于暴露 /retros/users 端点的方法,以下是相关代码(无需展示全部内容):
@GetMapping("/users")
public ResponseEntity getAllUsers(){
this.retroBoardAndCardService.getAllUsers();
return ResponseEntity.ok(Map.of("status",200,"message","Users retrieved. Should be in the console","time",LocalDateTime.now()));
}
这段代码会调用服务,并在控制台中显示用户信息。
接下来,打开 application.properties 文件,参见列表 13-9。
## DataSource
spring.h2.console.enabled=true
spring.datasource.generate-unique-name=false
spring.datasource.name=test-db
spring.jpa.show-sql=true
## Server
server.port=${PORT:8080}
## Consul
spring.config.import=consul://
## Application
spring.application.name=my-retro-app
logging.pattern.correlation=[${spring.application.name:},%X{traceId:-},%X{spanId:-}]
## Actuator Info
info.developer.name=Felipe
info.developer.email=felipe@email.com
info.api.version=1.0
management.endpoint.env.enabled=true
## Actuator
management.endpoints.web.exposure.include=health,info,metrics,prometheus
## Actuator Observations
management.observations.key-values.application=${spring.application.name}
## Actuator Metrics
management.metrics.distribution.percentiles-histogram.http.server.requests=true
## Actuator Tracing
management.tracing.sampling.probability=1.0
## Actuator Prometheus
management.prometheus.metrics.export.enabled=true
management.metrics.use-global-registry=true
列表 13-9 源文件:
src/main/resources/application.properties
在 application.properties 中,重要的是要指定应用程序的名称,即 spring.application.name=my-retro-app,以及 spring.config.import=consul://,这将使用 Consul 作为外部配置(尽管我们并没有指定任何内容)。