On this page
3. Spring Cloud Commons:通用抽象
服务发现,负载平衡和电路断路器等模式将它们带到一个通用的抽象层,可以由所有 Spring CloudClient 端使用,而与实现无关(例如,使用 Eureka 或 Consul 进行发现)。
3.1 @EnableDiscoveryClient
Spring Cloud Commons 提供了@EnableDiscoveryClient
Comments。这将通过META-INF/spring.factories
寻找DiscoveryClient
接口的实现。 Discovery Client 的实现在org.springframework.cloud.client.discovery.EnableDiscoveryClient
键下将配置类添加到spring.factories
。 DiscoveryClient
实现的示例包括Spring Cloud NetflixEureka,Spring Cloud Consul 发现和Spring Cloud Zookeeper 发现。
默认情况下,DiscoveryClient
的实现将本地 Spring Boot 服务器自动注册到远程发现服务器。可以通过在@EnableDiscoveryClient
中设置autoRegister=false
来禁用此行为。
Note
不再需要@EnableDiscoveryClient
。您可以在 Classpath 上放置一个DiscoveryClient
实现,以使 Spring Boot 应用程序向服务发现服务器注册。
3.1.1 健康 Metrics
Commons 创建了一个 Spring Boot HealthIndicator
,DiscoveryClient
实现可以通过实现DiscoveryHealthIndicator
参与其中。要禁用复合HealthIndicator
,请设置spring.cloud.discovery.client.composite-indicator.enabled=false
。将自动配置基于DiscoveryClient
的通用HealthIndicator
(DiscoveryClientHealthIndicator
)。要禁用它,请设置spring.cloud.discovery.client.health-indicator.enabled=false
。要禁用DiscoveryClientHealthIndicator
的描述字段,请设置spring.cloud.discovery.client.health-indicator.include-description=false
。否则,它可能会冒起泡沫,成为HealthIndicator
中的description
。
3.1.2OrderDiscoveryClient 实例
DiscoveryClient
接口扩展了Ordered
。当使用多个发现 Client 端时,这很有用,因为它允许您定义返回的发现 Client 端的 Sequences,类似于如何 OrderSpring 应用程序加载的 bean。默认情况下,任何DiscoveryClient
的 Sequences 都设置为0
。如果要为自定义DiscoveryClient
实现设置不同的 Sequences,则只需覆盖getOrder()
方法,以便它返回适合您的设置的值。除此之外,您可以使用属性来设置 Spring Cloud 提供的DiscoveryClient
实现的 Sequences,以及ConsulDiscoveryClient
,EurekaDiscoveryClient
和ZookeeperDiscoveryClient
。为此,只需将spring.cloud.{clientIdentifier}.discovery.order
(对于 Eureka 则为eureka.client.order
)属性设置为所需值。
3.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);
}
}
每个ServiceRegistry
实现都有自己的Registry
实现。
ZookeeperRegistration
与ZookeeperServiceRegistry
一起使用EurekaRegistration
与EurekaServiceRegistry
一起使用ConsulRegistration
与ConsulServiceRegistry
一起使用
如果使用的是ServiceRegistry
接口,则将需要为使用的ServiceRegistry
实现传递正确的Registry
实现。
3.2.1 ServiceRegistry 自动注册
默认情况下,ServiceRegistry
实现会自动注册正在运行的服务。要禁用该行为,可以设置:* @EnableDiscoveryClient(autoRegister=false)
以永久禁用自动注册。 * spring.cloud.service-registry.auto-registration.enabled=false
通过配置禁用行为。
ServiceRegistry 自动注册事件
服务自动注册时将触发两个事件。在注册服务之前会触发名为InstancePreRegisteredEvent
的第一个事件。注册服务后,将触发名为InstanceRegisteredEvent
的第二个事件。您可以注册ApplicationListener
(s)来监听和响应这些事件。
Note
如果spring.cloud.service-registry.auto-registration.enabled
设置为false
,则不会触发这些事件。
3.2.2 服务注册表 Actuator 端点
Spring Cloud Commons 提供了/service-registry
Actuator 端点。该端点依赖于 Spring Application Context 中的Registration
bean。使用 GET 调用/service-registry
返回Registration
的状态。对具有 JSON 正文的同一端点使用 POST 会将当前Registration
的状态更改为新值。 JSON 正文必须包含具有首选值的status
字段。请参阅更新状态时用于允许值的ServiceRegistry
实现的文档以及该状态返回的值。例如,Eureka 支持的状态为UP
,DOWN
,OUT_OF_SERVICE
和UNKNOWN
。
3.3 Spring RestTemplate 作为负载均衡器 Client 端
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;
}
}
Warning
RestTemplate
bean 不再通过自动配置创建。各个应用程序必须创建它。
URI 需要使用虚拟主机名(即服务名,而不是主机名)。功能区 Client 端用于创建完整的物理地址。有关RestTemplate
设置的详细信息,请参见RibbonAutoConfiguration。
3.4 Spring WebClient 作为负载均衡器 Client 端
WebClient
可以自动配置为使用LoadBalancerClient
。要创建负载平衡的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 需要使用虚拟主机名(即服务名,而不是主机名)。功能区 Client 端用于创建完整的物理地址。
3.4.1 重试失败的请求
可以将负载平衡的RestTemplate
配置为重试失败的请求。默认情况下,禁用此逻辑。您可以通过在应用程序的 Classpath 中添加Spring Retry来启用它。负载平衡的RestTemplate
支持某些与重试失败请求有关的功能区配置值。您可以使用client.ribbon.MaxAutoRetries
,client.ribbon.MaxAutoRetriesNextServer
和client.ribbon.OkToRetryOnAllOperations
属性。如果您想在 Classpath 上使用 Spring Retry 禁用重试逻辑,则可以设置spring.cloud.loadbalancer.retry.enabled=false
。有关这些属性的作用,请参见Ribbon documentation。
如果您想在重试中实现BackOffPolicy
,则需要创建LoadBalancedRetryFactory
类型的 bean 并覆盖createBackOffPolicy
方法:
@Configuration
public class MyConfiguration {
@Bean
LoadBalancedRetryFactory retryFactory() {
return new LoadBalancedRetryFactory() {
@Override
public BackOffPolicy createBackOffPolicy(String service) {
return new ExponentialBackOffPolicy();
}
};
}
}
Note
前面示例中的client
应该替换为 Ribbon 用户名。
如果要向重试功能中添加一个或多个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...
}
}};
}
};
}
}
3.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);
}
}
Tip
请注意,在前面的示例中,对普通RestTemplate
声明使用了@Primary
Comments,以消除不合格的@Autowired
注入的歧义。
Tip
如果看到诸如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
。
3.6 Spring WebFlux WebClient 作为负载均衡器 Client 端
可以将WebClient
配置为使用LoadBalancerClient
。如果spring-webflux
在 Classpath 上,则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
用于创建完整的物理地址。
3.7 忽略网络接口
有时,忽略某些命名的网络接口很有用,以便可以将它们从服务发现注册中排除(例如,在 Docker 容器中运行时)。可以设置正则表达式列表以使所需的网络接口被忽略。以下配置将忽略docker0
接口以及所有以veth
开头的接口:
application.yml.
spring:
cloud:
inetutils:
ignoredInterfaces:
- docker0
- veth.*
您还可以通过使用正则表达式列表来强制仅使用指定的网络地址,如以下示例所示:
bootstrap.yml.
spring:
cloud:
inetutils:
preferredNetworks:
- 192.168
- 10.0
您还可以强制仅使用站点本地地址,如以下示例所示:.application.yml
spring:
cloud:
inetutils:
useOnlySiteLocalInterfaces: true
有关构成站点本地地址的详细信息,请参见Inet4Address.html.isSiteLocalAddress()。
3.8 HTTPClient 端工厂
Spring Cloud Commons 提供了用于创建 Apache HTTPClient 端(ApacheHttpClientFactory
)和 OK HTTPClient 端(OkHttpClientFactory
)的 bean。仅当 OK HTTP jar 位于 Classpath 上时,才会创建OkHttpClientFactory
bean。另外,Spring Cloud Commons 提供了用于创建两个 Client 端都使用的连接 Management 器的 bean:ApacheHttpClientConnectionManagerFactory
用于 Apache HTTPClient 端,OkHttpClientConnectionPoolFactory
用于 OK HTTPClient 端。如果要自定义在下游项目中创建 HTTPClient 端的方式,则可以提供自己的这些 Bean 实现。另外,如果您提供类型为HttpClientBuilder
或OkHttpClient.Builder
的 bean,则默认工厂将使用这些构建器作为返回到下游项目的构建器的基础。您还可以通过将spring.cloud.httpclientfactories.apache.enabled
或spring.cloud.httpclientfactories.ok.enabled
设置为false
来禁用这些 bean 的创建。
3.9 启用的功能
Spring Cloud Commons 提供了/features
Actuator 端点。该端点返回 Classpath 上可用的功能以及是否启用了这些功能。返回的信息包括功能类型,名称,版本和供应商。
3.9.1 功能类型
“功能”有两种类型:抽象和命名。
抽象功能是定义接口或抽象类并创建实现的功能,例如DiscoveryClient
,LoadBalancerClient
或LockService
。抽象类或接口用于在上下文中查找该类型的 bean。显示的版本是bean.getClass().getPackage().getImplementationVersion()
。
命名功能是没有实现的特定类的功能,例如“ Circuit Breaker”,“ API Gateway”,“ Spring Cloud Bus”等。这些功能需要名称和 Bean 类型。
3.9.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(Foo.class)
.namedFeature(new NamedFeature("Bar Feature", Bar.class))
.abstractFeature(Baz.class)
.build();
}
这些 bean 中的每一个都应放入经过适当保护的@Configuration
中。
3.10 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.cloud.compatibility-verifier.enabled
设置为false
。如果您想覆盖兼容的 Spring Boot 版本,只需用兼容的 Spring Boot 版本的逗号分隔列表设置spring.cloud.compatibility-verifier.compatible-boot-versions
属性。