2. Spring Cloud Commons:通用抽象
诸如服务发现、负载平衡和断路器之类的模式适合于一个通用的抽象层,该抽象层可以由所有 Spring Cloud 客户端使用,独立于实现(例如,使用 Eureka 或 Consul 进行发现)。
2.1. @EnableDiscoveryClient
注解
Spring Cloud Commons 提供了 Comments。
这将查找 和 与 的接口的实现。
发现客户端的实现在 key 下添加一个配置类。
实现示例包括 Spring Cloud Netflix Eureka、Spring Cloud Consul Discovery 和 Spring Cloud Zookeeper Discovery。@EnableDiscoveryClient
DiscoveryClient
ReactiveDiscoveryClient
META-INF/spring.factories
spring.factories
org.springframework.cloud.client.discovery.EnableDiscoveryClient
DiscoveryClient
Spring Cloud 默认将提供阻塞和反应式服务发现客户端。
您可以通过设置 或 来轻松禁用阻塞和/或反应式客户端。
要完全禁用服务发现,您只需设置 .spring.cloud.discovery.blocking.enabled=false
spring.cloud.discovery.reactive.enabled=false
spring.cloud.discovery.enabled=false
默认情况下,的实现会自动向远程发现服务器注册本地 Spring Boot 服务器。
可以通过在 中设置来禁用此行为。DiscoveryClient
autoRegister=false
@EnableDiscoveryClient
@EnableDiscoveryClient 不再需要。
您可以将实现放在 Classpath 上,以使 Spring Boot 应用程序向服务发现服务器注册。DiscoveryClient |
2.1.1. 健康指标
Commons 自动配置以下 Spring Boot 健康指示器。
DiscoveryClientHealthIndicator
此运行状况指示器基于当前注册的实现。DiscoveryClient
-
要完全禁用,请将 .
spring.cloud.discovery.client.health-indicator.enabled=false
-
要禁用描述字段,请将 . 否则,它可能会作为卷起的 冒泡。
spring.cloud.discovery.client.health-indicator.include-description=false
description
HealthIndicator
-
要禁用服务检索,请设置 . 默认情况下,指示器调用 Client 端的方法。在具有许多注册服务的部署中,它也可能 在每次检查期间检索所有服务的成本很高。这将跳过服务检索,而是使用客户端的方法。
spring.cloud.discovery.client.health-indicator.use-services-query=false
getServices
probe
发现CompositeHealthContributor
此复合运行状况指示器基于所有已注册的 bean。要禁用,
设置。DiscoveryHealthIndicator
spring.cloud.discovery.client.composite-indicator.enabled=false
2.1.2. 订购 DiscoveryClient
实例
DiscoveryClient
interface 扩展了 .这在使用多重发现时非常有用
clients,因为它允许您定义返回的发现客户端的顺序,类似于
如何对 Spring 应用程序加载的 bean 进行排序。默认情况下,any 的顺序设置为 。如果您想为自定义实现设置不同的顺序,则只需覆盖
方法,以便它返回适合您设置的值。除此之外,您还可以使用
properties 设置由 Spring Cloud 提供的实现的顺序,其中包括 和 。为此,您只需将 (or for Eureka) 属性设置为所需的值。Ordered
DiscoveryClient
0
DiscoveryClient
getOrder()
DiscoveryClient
ConsulDiscoveryClient
EurekaDiscoveryClient
ZookeeperDiscoveryClient
spring.cloud.{clientIdentifier}.discovery.order
eureka.client.order
2.1.3. 简单发现客户端
如果 Classpath 中没有 Service-Registry 支持的,则将使用使用属性获取有关服务和实例信息的实例。DiscoveryClient
SimpleDiscoveryClient
有关可用实例的信息应通过以下格式的属性传递给:,其中 是公共前缀,然后是 stands
对于相关服务的 ID,while 表示实例的索引号
(如示例中所示,索引以 开头),然后是
实例可用的实际 URI。spring.cloud.discovery.client.simple.instances.service1[0].uri=http://s11:8080
spring.cloud.discovery.client.simple.instances
service1
[0]
0
uri
2.2. ServiceRegistry 服务
Commons 现在提供了一个接口,该接口提供诸如 和 之类的方法,这些方法允许您提供自定义注册服务。 是标记接口。ServiceRegistry
register(Registration)
deregister(Registration)
Registration
以下示例显示了正在使用的:ServiceRegistry
@Configuration
@EnableDiscoveryClient(autoRegister=false)
public class MyConfiguration {
private ServiceRegistry registry;
public MyConfiguration(ServiceRegistry registry) {
this.registry = registry;
}
// called through some external process, such as an event or a custom actuator endpoint
public void register() {
Registration registration = constructRegistration();
this.registry.register(registration);
}
}
每个 implementation 都有自己的 implementation。ServiceRegistry
Registry
-
ZookeeperRegistration
用于ZookeeperServiceRegistry
-
EurekaRegistration
用于EurekaServiceRegistry
-
ConsulRegistration
用于ConsulServiceRegistry
如果您正在使用该接口,则需要将
正确的实施 对于 您的 实施
正在使用。ServiceRegistry
Registry
ServiceRegistry
2.2.1. ServiceRegistry 自动注册
默认情况下,该实现会自动注册正在运行的服务。
要禁用该行为,您可以设置:
* 永久禁用自动注册。
* 通过配置禁用该行为。ServiceRegistry
@EnableDiscoveryClient(autoRegister=false)
spring.cloud.service-registry.auto-registration.enabled=false
ServiceRegistry 自动注册事件
当服务自动注册时,将触发两个事件。第一个事件(称为 )在注册服务之前触发。第二个
事件(称为 )在注册服务后触发。您可以注册一个 () 来监听和响应这些事件。InstancePreRegisteredEvent
InstanceRegisteredEvent
ApplicationListener
如果该属性设置为 ,则不会触发这些事件。spring.cloud.service-registry.auto-registration.enabled false |
2.2.2. Service Registry Actuator 端点
Spring Cloud Commons 提供了一个 actuator 端点。
此端点依赖于 Spring Application Context 中的 Bean。
使用 GET 调用将返回 .
对带有 JSON 正文的同一终端节点使用 POST 会将 current 的状态更改为新值。
JSON 正文必须包含具有首选值的字段。
请参阅您用于更新状态时允许的值的实施文档,以及为状态返回的值。
例如,Eureka 支持的状态为 、 、 和 。/service-registry
Registration
/service-registry
Registration
Registration
status
ServiceRegistry
UP
DOWN
OUT_OF_SERVICE
UNKNOWN
2.3. Spring RestTemplate 作为负载均衡器客户端
您可以将 配置为使用 Load-balancer 客户端。
要创建 load-balanced ,请创建一个并使用限定符,如下例所示:RestTemplate
RestTemplate
RestTemplate
@Bean
@LoadBalanced
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class MyClass {
@Autowired
private RestTemplate restTemplate;
public String doOtherStuff() {
String results = restTemplate.getForObject("http://stores/stores", String.class);
return results;
}
}
不再通过自动配置创建 Bean。
必须由各个应用程序创建。RestTemplate |
URI 需要使用虚拟主机名(即服务名称,而不是主机名)。 BlockingLoadBalancerClient 用于创建完整的物理地址。
要使用 load-balanced ,您需要在 Classpath 中具有 load-balancer 实现。
将 Spring Cloud LoadBalancer starter 添加到您的项目中,以便使用它。RestTemplate |
2.4. Spring WebClient 作为负载均衡器客户端
您可以配置为自动使用负载均衡器客户端。
要创建 load-balanced ,请创建一个并使用限定符,如下所示:WebClient
WebClient
WebClient.Builder
@Bean
@LoadBalanced
@Configuration
public class MyConfiguration {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}
public class MyClass {
@Autowired
private WebClient.Builder webClientBuilder;
public Mono<String> doOtherStuff() {
return webClientBuilder.build().get().uri("http://stores/stores")
.retrieve().bodyToMono(String.class);
}
}
URI 需要使用虚拟主机名(即服务名称,而不是主机名)。 Spring Cloud LoadBalancer 用于创建完整的物理地址。
如果要使用 ,则需要有一个负载均衡器
implementation 的 API 中。我们建议您将 Spring Cloud LoadBalancer starter 添加到您的项目中。
然后,在下面使用。@LoadBalanced WebClient.Builder ReactiveLoadBalancer |
2.4.1. 重试失败的请求
可以将负载均衡配置为重试失败的请求。
默认情况下,此逻辑处于禁用状态。
对于非反应版本(带有),您可以通过将 Spring Retry 添加到应用程序的 Classpath 来启用它。对于反应式版本(带有 .RestTemplate
RestTemplate
WebTestClient), you need to set `spring.cloud.loadbalancer.retry.enabled=true
如果要在 classpath 上使用 Spring Retry 或 Reactive Retry 禁用重试逻辑,则可以设置。spring.cloud.loadbalancer.retry.enabled=false
对于非反应式实现,如果你想在重试中实现 a,你需要创建一个 type 的 bean 并覆盖该方法。BackOffPolicy
LoadBalancedRetryFactory
createBackOffPolicy()
对于反应式实现,您只需通过设置为 来启用它。spring.cloud.loadbalancer.retry.backoff.enabled
false
您可以设置:
-
spring.cloud.loadbalancer.retry.maxRetriesOnSameServiceInstance
- 指示应在同一请求上重试多少次(对于每个选定的实例单独计数)ServiceInstance
-
spring.cloud.loadbalancer.retry.maxRetriesOnNextServiceInstance
- 指示应将请求重试新选择的次数ServiceInstance
-
spring.cloud.loadbalancer.retry.retryableStatusCodes
- 始终重试失败请求的状态代码。
对于反应式实现,您还可以设置:
- - 设置最短退避持续时间(默认为 5 毫秒)
- - 设置最大退避持续时间(默认为最大毫秒长值)
- - 设置用于计算每次调用的实际回退持续时间的抖动(默认为 0.5)。spring.cloud.loadbalancer.retry.backoff.minBackoff
spring.cloud.loadbalancer.retry.backoff.maxBackoff
spring.cloud.loadbalancer.retry.backoff.jitter
对于反应式实现,您还可以实现自己的实现,以便对负载均衡的调用重试进行更详细的控制。LoadBalancerRetryPolicy
单个 Loadbalancer 客户端可以使用与上述相同的属性单独配置,但前缀为 where 是负载均衡器的名称。spring.cloud.loadbalancer.clients.<clientId>.* clientId |
对于负载平衡的重试,默认情况下,我们包装 bean 以选择与之前选择的实例不同的实例(如果可用)。您可以通过将 的值设置为 来禁用此行为。ServiceInstanceListSupplier RetryAwareServiceInstanceListSupplier spring.cloud.loadbalancer.retry.avoidPreviousInstance false |
@Configuration
public class MyConfiguration {
@Bean
LoadBalancedRetryFactory retryFactory() {
return new LoadBalancedRetryFactory() {
@Override
public BackOffPolicy createBackOffPolicy(String service) {
return new ExponentialBackOffPolicy();
}
};
}
}
如果要将一个或多个 implementations 添加到重试功能中,则需要
创建一个 Bean 类型并返回数组
您希望用于给定服务,如下例所示:RetryListener
LoadBalancedRetryListenerFactory
RetryListener
@Configuration
public class MyConfiguration {
@Bean
LoadBalancedRetryListenerFactory retryListenerFactory() {
return new LoadBalancedRetryListenerFactory() {
@Override
public RetryListener[] createRetryListeners(String service) {
return new RetryListener[]{new RetryListener() {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
//TODO Do you business...
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
//TODO Do you business...
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
//TODO Do you business...
}
}};
}
};
}
}
2.5. 多个 RestTemplate
对象
如果你想要一个没有负载均衡的 bean,请创建一个 bean 并注入它。
要访问 load-balanced ,请在创建 时使用限定符,如下例所示:RestTemplate
RestTemplate
RestTemplate
@LoadBalanced
@Bean
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
RestTemplate loadBalanced() {
return new RestTemplate();
}
@Primary
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class MyClass {
@Autowired
private RestTemplate restTemplate;
@Autowired
@LoadBalanced
private RestTemplate loadBalanced;
public String doOtherStuff() {
return loadBalanced.getForObject("http://stores/stores", String.class);
}
public String doStuff() {
return restTemplate.getForObject("http://example.com", String.class);
}
}
请注意,在前面的示例中,对 plain 声明使用了 annotation 来消除不合格注入的歧义。@Primary RestTemplate @Autowired |
如果您看到诸如 、 、 尝试注入或设置 等错误。java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89 RestOperations spring.aop.proxyTargetClass=true |
2.6. 多个 WebClient 对象
如果你想要一个没有负载均衡的 bean,请创建一个 bean 并注入它。
要访问 load-balanced ,请在创建 时使用限定符,如下例所示:WebClient
WebClient
WebClient
@LoadBalanced
@Bean
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
WebClient.Builder loadBalanced() {
return WebClient.builder();
}
@Primary
@Bean
WebClient.Builder webClient() {
return WebClient.builder();
}
}
public class MyClass {
@Autowired
private WebClient.Builder webClientBuilder;
@Autowired
@LoadBalanced
private WebClient.Builder loadBalanced;
public Mono<String> doOtherStuff() {
return loadBalanced.build().get().uri("http://stores/stores")
.retrieve().bodyToMono(String.class);
}
public Mono<String> doStuff() {
return webClientBuilder.build().get().uri("http://example.com")
.retrieve().bodyToMono(String.class);
}
}
2.7. Spring WebFlux WebClient
作为负载均衡器客户端
Spring WebFlux 可以使用反应式和非反应式配置,如主题所述:WebClient
2.7.1. 带有ReactorLoadBalancerExchangeFilterFunction
的Spring WebFlux WebClient
您可以配置为使用 .
如果你将 Spring Cloud LoadBalancer starter 添加到你的项目中
如果位于 Classpath 上,则自动配置。
以下示例显示如何配置 以使用 reactive load-balancer:WebClient
ReactiveLoadBalancer
spring-webflux
ReactorLoadBalancerExchangeFilterFunction
WebClient
public class MyClass {
@Autowired
private ReactorLoadBalancerExchangeFilterFunction lbFunction;
public Mono<String> doOtherStuff() {
return WebClient.builder().baseUrl("http://stores")
.filter(lbFunction)
.build()
.get()
.uri("/stores")
.retrieve()
.bodyToMono(String.class);
}
}
URI 需要使用虚拟主机名(即服务名称,而不是主机名)。
用于创建完整的物理地址。ReactorLoadBalancer
2.7.2. 带有非反应式负载均衡器客户端的 Spring WebFlux WebClient
如果 在 Classpath 上,则自动配置。但是请注意,此
在后台使用非反应式客户端。
以下示例显示如何配置 以使用 load-balancer:spring-webflux
LoadBalancerExchangeFilterFunction
WebClient
public class MyClass {
@Autowired
private LoadBalancerExchangeFilterFunction lbFunction;
public Mono<String> doOtherStuff() {
return WebClient.builder().baseUrl("http://stores")
.filter(lbFunction)
.build()
.get()
.uri("/stores")
.retrieve()
.bodyToMono(String.class);
}
}
URI 需要使用虚拟主机名(即服务名称,而不是主机名)。
用于创建完整的物理地址。LoadBalancerClient
警告:此方法现已弃用。 我们建议您改用 WebFlux 和反应式 Load-Balancer。
2.8. 忽略网络接口
有时,忽略某些命名网络接口很有用,这样就可以将它们从 Service Discovery 注册中排除(例如,在 Docker 容器中运行时)。
可以设置正则表达式列表,以忽略所需的网络接口。
以下配置将忽略 interface 和所有以 :docker0
veth
spring: cloud: inetutils: ignoredInterfaces: - docker0 - veth.*
您还可以使用正则表达式列表强制仅使用指定的网络地址,如下例所示:
spring: cloud: inetutils: preferredNetworks: - 192.168 - 10.0
您还可以强制仅使用站点本地地址,如下例所示:
spring: cloud: inetutils: useOnlySiteLocalInterfaces: true
请参阅 Inet4Address.html.isSiteLocalAddress() 了解有关站点本地地址的更多详细信息。
2.9. HTTP 客户端工厂
Spring Cloud Commons 提供了用于创建 Apache HTTP 客户端 () 和 OK HTTP 客户端 () 的 bean。
仅当 OK HTTP jar 位于 Classpath 上时,才会创建 Bean。
此外,Spring Cloud Commons 还提供了用于创建两个客户端都使用的连接管理器的 bean:用于 Apache HTTP 客户端和 OK HTTP 客户端。
如果要自定义在下游项目中创建 HTTP Client 端的方式,则可以提供这些 bean 的自己的实现。
此外,如果提供 或 类型的 bean,则默认工厂使用这些构建器作为返回到下游项目的构建器的基础。
您还可以通过将 或 设置为 来禁用这些 bean 的创建。ApacheHttpClientFactory
OkHttpClientFactory
OkHttpClientFactory
ApacheHttpClientConnectionManagerFactory
OkHttpClientConnectionPoolFactory
HttpClientBuilder
OkHttpClient.Builder
spring.cloud.httpclientfactories.apache.enabled
spring.cloud.httpclientfactories.ok.enabled
false
2.10. 启用的功能
Spring Cloud Commons 提供了一个 actuator 端点。
此端点返回 Classpath 上可用的功能以及这些功能是否已启用。
返回的信息包括功能类型、名称、版本和供应商。/features
2.10.1. 特征类型
有两种类型的 “特征”:抽象的和命名的。
抽象功能是其中定义了接口或抽象类并且创建的实现(如 、 、 或 )的功能。
抽象类或接口用于在上下文中查找该类型的 bean。
显示的版本为 。DiscoveryClient
LoadBalancerClient
LockService
bean.getClass().getPackage().getImplementationVersion()
命名功能是没有它们实现的特定类的功能。这些功能包括 “Circuit Breaker”、“API Gateway”、“Spring Cloud Bus” 等。这些功能需要一个 name 和一个 bean 类型。
2.10.2. 声明功能
任何模块都可以声明任意数量的 bean,如下例所示:HasFeature
@Bean
public HasFeatures commonsFeatures() {
return HasFeatures.abstractFeatures(DiscoveryClient.class, LoadBalancerClient.class);
}
@Bean
public HasFeatures consulFeatures() {
return HasFeatures.namedFeatures(
new NamedFeature("Spring Cloud Bus", ConsulBusAutoConfiguration.class),
new NamedFeature("Circuit Breaker", HystrixCommandAspect.class));
}
@Bean
HasFeatures localFeatures() {
return HasFeatures.builder()
.abstractFeature(Something.class)
.namedFeature(new NamedFeature("Some Other Feature", Someother.class))
.abstractFeature(Somethingelse.class)
.build();
}
这些豆子中的每一个都应该放入适当保护的 .@Configuration
2.11. Spring Cloud 兼容性验证
由于一些用户在设置 Spring Cloud 应用程序时遇到问题,我们决定 添加兼容性验证机制。如果您当前的设置不兼容,它将中断 以及 Spring Cloud 需求,以及一份报告,显示到底出了什么问题。
目前,我们验证将哪个版本的 Spring Boot 添加到您的 Classpath 中。
报告示例
*************************** APPLICATION FAILED TO START *************************** Description: Your project setup is incompatible with our requirements due to following reasons: - Spring Boot [2.1.0.RELEASE] is not compatible with this Spring Cloud release train Action: Consider applying the following actions: - Change Spring Boot version to one of the following versions [1.2.x, 1.3.x] . You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn]. If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.
要禁用此功能,请设置为 。
如果要覆盖兼容的 Spring Boot 版本,只需使用逗号分隔的列表设置该属性
兼容的 Spring Boot 版本。spring.cloud.compatibility-verifier.enabled
false
spring.cloud.compatibility-verifier.compatible-boot-versions