2. Spring Cloud Commons:常见抽象
服务发现、负载平衡和断路器等模式适用于所有 Spring Cloud 客户端都可以使用的通用抽象层,与实现无关(例如,使用 Eureka 或 Consul 进行发现)。
2.1.@EnableDiscoveryClient
注解
Spring 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 服务器注册到远程发现服务器。
可以通过将autoRegister=false
在@EnableDiscoveryClient
.
@EnableDiscoveryClient 不再需要。
你可以将一个DiscoveryClient 实现,以使 Spring Boot 应用程序向服务发现服务器注册。 |
2.1.1. 健康指标
Commons 自动配置以下 Spring Boot 运行状况指示器。
发现客户端健康指标
此健康指标基于当前注册的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
方法。
发现复合健康贡献者
该综合健康指标基于所有注册的DiscoveryHealthIndicator
豆。要禁用,
设置spring.cloud.discovery.client.composite-indicator.enabled=false
.
2.1.2. 订购DiscoveryClient
实例
DiscoveryClient
接口扩展Ordered
.这在使用多重发现时非常有用
clients,因为它允许您定义返回的发现客户端的顺序,类似于
如何对 Spring 应用程序加载的 bean 进行排序。默认情况下,任何DiscoveryClient
设置为0
.如果您想为自定义设置不同的顺序DiscoveryClient
实现,你只需要覆盖
这getOrder()
方法,以便返回适合您的设置的值。除此之外,您还可以使用
属性来设置DiscoveryClient
Spring Cloud 提供的实现等ConsulDiscoveryClient
,EurekaDiscoveryClient
和ZookeeperDiscoveryClient
.为此,您只需将spring.cloud.{clientIdentifier}.discovery.order
(或eureka.client.order
对于 Eureka)属性设置为所需值。
2.1.3. SimpleDiscovery客户端
如果没有 Service-Registry 支持的DiscoveryClient
在类路径中,SimpleDiscoveryClient
instance,它使用属性来获取有关服务和实例的信息。
有关可用实例的信息应以以下格式传递给 via 属性: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. 服务注册表
共享资源现在提供了一个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
接口,您将需要将
正确Registry
实现ServiceRegistry
实施你
正在使用。
2.2.1. ServiceRegistry 自动注册
默认情况下,ServiceRegistry
实现会自动注册正在运行的服务。
要禁用该行为,您可以设置:
*@EnableDiscoveryClient(autoRegister=false)
永久禁用自动注册。
*spring.cloud.service-registry.auto-registration.enabled=false
通过配置禁用该行为。
ServiceRegistry 自动注册事件
服务自动注册时将触发两个事件。第一个事件称为InstancePreRegisteredEvent
,在服务注册之前触发。第二个
事件,称为InstanceRegisteredEvent
,在服务注册后触发。您可以注册一个ApplicationListener
(s) 倾听这些事件并做出反应。
如果spring.cloud.service-registry.auto-registration.enabled 属性设置为false . |
2.2.2. Service Registry Actuator 端点
Spring Cloud Commons 提供了一个/service-registry
执行器端点。
此端点依赖于Registration
bean 在 Spring 应用程序上下文中。
叫/service-registry
使用 GET 返回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;
}
}
一个RestTemplate Bean 不再通过自动配置创建。
单个应用程序必须创建它。 |
URI 需要使用虚拟主机名(即服务名称,而不是主机名)。 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 需要使用虚拟主机名(即服务名称,而不是主机名)。 Spring Cloud LoadBalancer 用于创建完整的物理地址。
如果要使用@LoadBalanced WebClient.Builder ,您需要有一个负载均衡器
在类路径中实现。我们建议您将 Spring Cloud LoadBalancer Starters添加到您的项目中。
然后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
并覆盖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
以更详细地控制负载平衡的呼叫重试。
单个 Loadbalancer 客户端可以单独配置为与上述相同的属性,但前缀是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
并返回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
豆子并注入它。
访问负载平衡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);
}
}
请注意@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对象
如果你想要一个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 WebFluxWebClient
作为负载均衡器客户端
Spring WebFlux 可以处理响应式和非响应式WebClient
配置,如主题所述:
2.7.1. 春季 WebFluxWebClient
跟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 WebFluxWebClient
使用非响应式负载均衡器客户端
如果spring-webflux
在类路径上,LoadBalancerExchangeFilterFunction
是自动配置的。但请注意,此在后台使用非响应式客户端。以下示例演示如何配置WebClient
要使用 load-balancer,请执行以下作:
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. 忽略网络接口
有时,忽略某些命名网络接口很有用,以便可以将它们从服务发现注册中排除(例如,在 Docker 容器中运行时)。可以设置正则表达式列表以忽略所需的网络接口。以下配置忽略docker0
interface 和所有以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
).
这OkHttpClientFactory
仅当 OK HTTP jar 位于类路径上时,才会创建 bean。
此外,Spring Cloud Commons 还提供了用于创建两个客户端使用的连接管理器的 bean:ApacheHttpClientConnectionManagerFactory
对于 Apache HTTP 客户端和OkHttpClientConnectionPoolFactory
对于 OK HTTP 客户端。
如果您想自定义在下游项目中创建 HTTP 客户端的方式,您可以提供这些 Bean 的自己的实现。
此外,如果您提供类型为HttpClientBuilder
或OkHttpClient.Builder
,默认工厂使用这些建设者作为返回下游项目的建设者的基础。
您还可以通过将spring.cloud.httpclientfactories.apache.enabled
或spring.cloud.httpclientfactories.ok.enabled
自false
.
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();
}
这些豆子中的每一个都应该放在适当的保护下@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
带有逗号分隔列表的属性
兼容的 Spring Boot 版本。