共计 9776 个字符,预计需要花费 25 分钟才能阅读完成。
Spring Cloud Commons:通用的抽象
服务发现、负载均衡和断路器等模式适用于所有 Spring Cloud 客户端都可以使用的通用抽象层,独立于实现(例如,使用 Eureka 或 Consul 发现)。
@EnableDiscoveryClient
Spring Cloud Commons 提供 @EnableDiscoveryClient 注解,这将使用 META-INF/spring.factories 查找 DiscoveryClient 接口的实现。Discovery Client 的实现将配置类添加到 org.springframework.cloud.client.discovery.EnableDiscoveryClient 键下的 spring.factories,DiscoveryClient 实现的示例包括 Spring Cloud Netflix Eureka,Spring Cloud Consul Discovery 和 Spring Cloud Zookeeper Discovery。
默认情况下,DiscoveryClient 的实现会使用远程发现服务器自动注册本地 Spring Boot 服务器,通过在 @EnableDiscoveryClient 中设置 autoRegister=false 可以禁用此行为。
@EnableDiscoveryClient 已不再需要,你可以在类路径上放置 DiscoveryClient 实现,以使 Spring Boot 应用程序向服务发现服务器注册。
健康指示器
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 的 description 字段,请设置 spring.cloud.discovery.client.health-indicator.include-description=false,否则,它可能会像卷起的 HealthIndicator 的 description 一样冒出来。
排序 DiscoveryClient 实例
DiscoveryClient 接口扩展了 Ordered,这在使用多个发现客户端时很有用,因为它允许你定义返回的发现客户端的顺序,类似于你可以如何排序 Spring 应用程序加载的 bean。默认情况下,任何 DiscoveryClient 的顺序都设置为 0,如果要为自定义 DiscoveryClient 实现设置不同的顺序,只需重写 getOrder() 方法,以便它返回适合你的设置的值。除此之外,你还可以使用属性来设置 Spring Cloud 提供的 DiscoveryClient 实现的顺序,其中包括 ConsulDiscoveryClient,EurekaDiscoveryClient 和 ZookeeperDiscoveryClient,为此,你只需将 spring.cloud.{clientIdentifier}.discovery.order(或 Eureka 的 eureka.client.order)属性设置为所需的值。
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 实现。
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,则不会触发这些事件。
Service Registry Actuator 端点
Spring Cloud Commons 提供 /service-registry 执行器端点,此端点依赖于 Spring Application Context 中的 Registration bean,使用 GET 调用 /service-registry 返回 Registration 的状态,将 POST 用于具有 JSON 体的同一端点会将当前 Registration 的状态更改为新值,JSON 体必须包含具有首选值的 status 字段。在更新状态和为状态返回的值时,请参阅用于允许值的 ServiceRegistry 实现的文档,例如,Eureka 支持的状态是 UP、DOWN、OUT_OF_SERVICE 和 UNKNOWN。
Spring RestTemplate 作为负载均衡客户端
RestTemplate 可以自动配置为使用 ribbon,要创建负载均衡的 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 需要使用虚拟主机名(即服务名称,而不是主机名),Ribbon 客户端用于创建完整的物理地址,有关如何设置 RestTemplate 的详细信息,请参见 RibbonAutoConfiguration。
Spring WebClient 作为负载均衡客户端
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 需要使用虚拟主机名(即服务名称,而不是主机名),Ribbon 客户端用于创建完整的物理地址。
重试失败的请求
可以将负载均衡的 RestTemplate 配置为重试失败的请求,默认情况下,禁用此逻辑,你可以通过将 Spring Retry 添加到应用程序的类路径来启用它。负载均衡的 RestTemplate 支持与重试失败的请求相关的一些 Ribbon 配置值,你可以使用 client.ribbon.MaxAutoRetries、client.ribbon.MaxAutoRetriesNextServer 和 client.ribbon.OkToRetryOnAllOperations 属性,如果要在类路径上使用 Spring Retry 禁用重试逻辑,可以设置 spring.cloud.loadbalancer.retry.enabled=false,有关这些属性的说明,请参阅 Ribbon 文档。
如果要在重试中实现 BackOffPolicy,则需要创建 LoadBalancedRetryFactory 类型的 bean 并覆盖 createBackOffPolicy 方法:
@Configuration
public class MyConfiguration {
@Bean
LoadBalancedRetryFactory retryFactory() {
return new LoadBalancedRetryFactory() {
@Override
public BackOffPolicy createBackOffPolicy(String service) {
return new ExponentialBackOffPolicy();
}
};
}
}
前面示例中的 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…
}
}};
}
};
}
}
多个 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。
Spring WebFlux WebClient 作为负载均衡客户端
可以将 WebClient 配置为使用 LoadBalancerClient,如果 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 用于创建完整的物理地址。
忽略网络接口
有时,忽略某些命名的网络接口以便从 Service Discovery 注册中排除它们(例如,在 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()。
HTTP 客户端工厂
Spring Cloud Commons 提供用于创建 Apache HTTP 客户端(ApacheHttpClientFactory)和 OK HTTP 客户端(OkHttpClientFactory)的 bean,仅当 OK HTTP jar 位于类路径上时,才会创建 OkHttpClientFactory bean。此外,Spring Cloud Commons 提供了创建用于两个客户端使用的连接管理器的 bean:Apache HTTP 客户端的 ApacheHttpClientConnectionManagerFactory 和 OK HTTP 客户端的 OkHttpClientConnectionPoolFactory。如果要自定义在下游项目中创建 HTTP 客户端的方式,可以提供自己的这些 bean 实现,此外,如果你提供类型为 HttpClientBuilder 或 OkHttpClient.Builder 的 bean,则默认工厂使用这些构建器作为返回到下游项目的构建器的基础,你还可以通过将 spring.cloud.httpclientfactories.apache.enabled 或 spring.cloud.httpclientfactories.ok.enabled 设置为 false 来禁用这些 bean 的创建。
启用功能
Spring Cloud Commons 提供 /features 执行器端点,此端点返回类路径上可用的功能以及它们是否已启用,返回的信息包括功能类型、名称、版本和供应商。
功能类型
有两种类型的 ’ 功能 ’:抽象和命名。
抽象功能是定义接口或抽象类并创建实现(如 DiscoveryClient、LoadBalancerClient 或 LockService)的功能,抽象类或接口用于在上下文中查找该类型的 bean,显示的版本是 bean.getClass().getPackage().getImplementationVersion()。
命名功能是没有他们实现的特定类的功能,例如“断路器”,“API 网关”,“Spring Cloud Bus”等,这些功能需要名称和 bean 类型。
声明功能
任何模块都可以声明任意数量的 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 中。
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 Boot 版本列表设置 spring.cloud.compatibility-verifier.compatible-boot-versions 属性。
上一篇:Spring Cloud Context:应用程序上下文服务