2. Spring Cloud Commons: Common Abstractions
诸如服务发现、负载均衡和断路器等模式可被抽象为一个通用层,供所有 Spring Cloud 客户端使用,且与具体实现(例如使用 Eureka 或 Consul 进行服务发现)无关。
将以下 java 开发 Spring 框架 英文网站的html内容翻译成中文,保持html结构和标签名称不变,结果以json结构返回,
2.1. The @EnableDiscoveryClient Annotation
@EnableDiscoveryClient AnnotationSpring Cloud Commons 提供了 @EnableDiscoveryClient 注解。该注解用于查找实现了 DiscoveryClient 和 ReactiveDiscoveryClient 接口的实现类,并带有 META-INF/spring.factories 注解。发现客户端的实现类会将一个配置类添加到 spring.factories 中,键为 org.springframework.cloud.client.discovery.EnableDiscoveryClient。DiscoveryClient 的示例实现包括 Spring Cloud Netflix Eureka、Spring Cloud Consul Discovery 和 Spring Cloud Zookeeper Discovery。
Spring Cloud 将默认提供阻塞式和响应式服务发现客户端。您可以通过设置 spring.cloud.discovery.blocking.enabled=false 或 spring.cloud.discovery.reactive.enabled=false 轻松禁用阻塞式和/或响应式客户端。若要完全禁用服务发现功能,只需设置 spring.cloud.discovery.enabled=false 即可。
默认情况下,DiscoveryClient 的实现会将本地 Spring Boot 服务器自动注册到远程发现服务器。可以通过在 @EnableDiscoveryClient 中设置 autoRegister=false 来禁用此行为。
@EnableDiscoveryClient 已不再需要。您可以在类路径中放置一个 DiscoveryClient 的实现,以使 Spring Boot 应用程序注册到服务发现服务器。 |
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传播出去。 -
要禁用服务检索,请将
spring.cloud.discovery.client.health-indicator.use-services-query=false设置为禁用状态。
默认情况下,该指示器会调用客户端的getServices方法。在注册服务数量较多的部署环境中,每次检查时都检索所有服务可能过于昂贵。这将跳过服务检索步骤,转而使用客户端的probe方法。
DiscoveryCompositeHealthContributor
此复合健康指标基于所有已注册的 DiscoveryHealthIndicator 个 Bean。要禁用它,请设置 spring.cloud.discovery.client.composite-indicator.enabled=false。
2.1.2. 排序DiscoveryClient个实例
DiscoveryClient 接口扩展 Ordered。这在使用多个发现客户端时非常有用,因为它允许您定义返回的发现客户端的顺序,类似于您可以对 Spring 应用程序加载的 Bean 进行排序的方式。默认情况下,任何 DiscoveryClient 的顺序设置为 0。如果您希望为自定义 DiscoveryClient 实现设置不同的顺序,只需重写 getOrder() 方法,使其返回适用于您环境的值即可。除此之外,您还可以通过属性来设置由 Spring Cloud 提供的 DiscoveryClient 实现的顺序,例如 ConsulDiscoveryClient、EurekaDiscoveryClient 和 ZookeeperDiscoveryClient。要实现此目的,您只需将 spring.cloud.{clientIdentifier}.discovery.order(或针对 Eureka 的 eureka.client.order)属性设置为所需的值。
2.1.3. 简单发现客户端
如果类路径中没有基于服务注册中心的 DiscoveryClient,则将使用 SimpleDiscoveryClient 实例,该实例通过属性获取服务和实例的相关信息。
可用实例的信息应通过以下格式的属性传递:spring.cloud.discovery.client.simple.instances.service1[0].uri=http://s11:8080,其中 spring.cloud.discovery.client.simple.instances 是公共前缀,service1 表示所涉及服务的ID,[0] 表示实例的索引编号(如示例所示,索引从 0 开始),而 uri 的值即为该实例实际可用的URI。
2.2. 服务注册中心
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);
}
}
每个 ServiceRegistry 实现都有其自身的 Registry 实现。
-
ZookeeperRegistration与ZookeeperServiceRegistry一起使用 -
EurekaRegistration与EurekaServiceRegistry一起使用 -
ConsulRegistration与ConsulServiceRegistry一起使用
如果您正在使用 ServiceRegistry 接口,则需要为所使用的 ServiceRegistry 实现传递正确的 Registry 实现。
2.2.1. ServiceRegistry 自动注册
默认情况下,ServiceRegistry 实现会自动注册运行中的服务。要禁用此行为,您可以设置:
@EnableDiscoveryClient(autoRegister=false)以永久禁用自动注册。spring.cloud.service-registry.auto-registration.enabled=false通过配置禁用该行为。
服务注册表自动注册事件
当服务自动注册时,会触发两个事件。第一个事件,称为InstancePreRegisteredEvent,在服务注册前触发。第二个事件,称为InstanceRegisteredEvent,在服务注册后触发。您可以注册一个或多个ApplicationListener(监听器)来监听并响应这些事件。
这些事件在将 spring.cloud.service-registry.auto-registration.enabled 属性设置为 false 时不会触发。 |
2.2.2. 服务注册表执行器端点
Spring Cloud Commons 提供了一个 /service-registry 指标端点。该端点依赖于 Spring 应用上下文中的一个 Registration Bean。通过 GET 请求调用 /service-registry 可返回 Registration 的状态。使用 POST 请求向同一端点发送包含 JSON 数据体的请求,可将当前 Registration 的状态更改为新值。JSON 数据体必须包含 status 字段,并指定期望的新值。请参阅您所使用的 ServiceRegistry 实现的文档,以了解更新状态时允许的取值范围以及状态返回值。例如,Eureka 支持的状态包括 UP、DOWN、OUT_OF_SERVICE 和 UNKNOWN。
2.3. 使用 Spring RestTemplate 实现负载均衡客户端
您可以配置一个 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;
}
}
A Individual applications must create it. |
URI 需要使用虚拟主机名(即服务名称,而不是主机名称)。<br>BlockingLoadBalancerClient 用于创建完整的物理地址。
要使用负载均衡的RestTemplate,您需要在类路径中包含一个负载均衡器实现。请将Spring Cloud LoadBalancer starter添加到您的项目中以使用它。 |
2.4. Spring WebClient作为负载均衡客户端
您可以将 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 需要使用虚拟主机名(即服务名称,而非主机名)。</p><p>Spring Cloud LoadBalancer 用于创建完整的物理地址。
如果您想使用@LoadBalanced WebClient.Builder,您需要在类路径中有负载均衡器实现。我们建议您向项目中添加Spring Cloud LoadBalancerStarters。然后,在底层会使用ReactiveLoadBalancer。 |
2.4.1. 失败请求重试
负载均衡的RestTemplate可以配置为重试失败的请求。默认情况下,此逻辑是禁用的。对于非响应式版本(带有RestTemplate),您可以通过将Spring Retry添加到应用程序的类路径来启用它。对于响应式版本(带有WebTestClient), you need to set `spring.cloud.loadbalancer.retry.enabled=true。
如果您希望禁用 Spring Retry 或 Reactive Retry 的重试逻辑(当类路径中存在这些依赖时),可以设置 spring.cloud.loadbalancer.retry.enabled=false。
对于非响应式实现,如果您希望在重试中实现 BackOffPolicy,则需要创建一个类型为 LoadBalancedRetryFactory 的 Bean,并重写 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- 在其上始终重试失败请求的状态码。
对于响应式实现,您可以另外设置:
- spring.cloud.loadbalancer.retry.backoff.minBackoff - 设置最小退避时间(默认为5毫秒)
- spring.cloud.loadbalancer.retry.backoff.maxBackoff - 设置最大退避时间(默认为毫秒的最大长值)
- spring.cloud.loadbalancer.retry.backoff.jitter - 设置用于计算每次调用的实际退避时间的抖动(默认为0.5)。
对于响应式实现,您还可以实现自己的 LoadBalancerRetryPolicy,以对负载均衡调用的重试过程进行更细致的控制。
单个负载均衡客户端可单独配置,其属性与上文所述相同,但前缀为 spring.cloud.loadbalancer.clients.<clientId>.*,其中 clientId 是负载均衡器的名称。 |
对于负载均衡重试,默认情况下,我们会将 ServiceInstanceListSupplier Bean 包装在 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();
}
};
}
}
如果您希望为重试功能添加一个或多个 RetryListener 实现,您需要创建一个类型为 LoadBalancedRetryListenerFactory 的 Bean,并返回您希望为特定服务使用的 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 对象
如果您想要一个非负载均衡的 RestTemplate,请创建一个 RestTemplate 类型的 Bean 并将其注入。
要访问负载均衡的 RestTemplate,请在创建您的 @Bean 时使用 @LoadBalanced 限定符,如下例所示:
@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);
}
}
注意在前一个示例中,对普通 RestTemplate 声明使用了 @Primary 注解,以消除对未限定的 @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对象
如果您想要一个非负载均衡的 WebClient,请创建一个 WebClient 类型的 Bean 并将其注入。
要访问负载均衡的 WebClient,请在创建您的 @Bean 时使用 @LoadBalanced 限定符,如下例所示:
@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. Spring WebFlux WebClient 与 ReactorLoadBalancerExchangeFilterFunction
您可以配置WebClient以使用ReactiveLoadBalancer。
如果将Spring Cloud LoadBalancer starter添加到项目中,且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
如果 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 与响应式负载均衡器。
2.8. 忽略网络接口
有时,忽略某些命名的网络接口会很有用,以便将它们从服务发现注册中排除(例如,在 Docker 容器中运行时)。可以通过设置正则表达式列表,来指定需要被忽略的网络接口。以下配置会忽略 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 客户端(ApacheHttpClientFactory)和 OK HTTP 客户端(OkHttpClientFactory)的 Bean。
只有当 OK HTTP 的 JAR 在类路径上时才会创建 OkHttpClientFactory Bean。
此外,Spring Cloud Commons 还提供了用于两个客户端连接管理器的 Bean:ApacheHttpClientConnectionManagerFactory 是 Apache HTTP 客户端使用的,OkHttpClientConnectionPoolFactory 是 OK HTTP 客户端使用的。
如果您希望在下游项目中自定义如何创建 HTTP 客户端,则可以提供这些 Bean 的自定义实现。
另外,如果您提供了类型为 HttpClientBuilder 或 OkHttpClient.Builder 的 Bean,则默认工厂会使用这些构建器作为向下游项目返回的构建器的基础。
您还可以通过将 spring.cloud.httpclientfactories.apache.enabled 或 spring.cloud.httpclientfactories.ok.enabled 设置为 false 来禁用这些 Bean 的创建。
2.10. 已启用的功能
Spring Cloud Commons 提供了一个 /features 操作端点。此端点返回类路径上可用的功能及其是否已启用的信息。返回的信息包括功能类型、名称、版本和提供商。
2.10.1. 功能类型
有两种类型的‘特性’:抽象特性和命名特性。
抽象功能是指在接口或抽象类中定义的功能,其具体实现由创建的类提供,例如 DiscoveryClient、LoadBalancerClient 或 LockService。抽象类或接口用于在上下文中查找该类型的 Bean。当前显示的版本是 bean.getClass().getPackage().getImplementationVersion()。
命名功能是指那些没有特定实现类的功能。这些功能包括“熔断器”、“API 网关”、“Spring Cloud Bus”等。这些功能需要一个名称和一个 Bean 类型。
2.10.2. 声明功能
任何模块都可以声明任意数量的HasFeature个 bean,如下面的示例所示:
@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();
}
这些 bean 中的每一个都应该放在一个适当保护的 @Configuration 里。
2.11. Spring Cloud 兼容性验证
由于一些用户在设置 Spring Cloud 应用程序时遇到问题,我们决定添加兼容性验证机制。 它将在当前设置与 Spring Cloud 要求不兼容时中断,同时显示报告,显示具体出错内容。
当前正在验证Spring Boot版本已添加到类路径。
报表范例
*************************** 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.cloud.compatibility-verifier.enabled 设置为 false。 若要覆盖兼容的 Spring Boot 版本,请使用逗号分隔的列表设置 spring.cloud.compatibility-verifier.compatible-boot-versions 属性。