Spring Cloud Alibaba Blog | https://sca.aliyun.com Spring Cloud Alibaba Blog
文档
社区
联系我们
学习
解决方案
中文

通用抽象

Spring 教程

3. Spring Cloud Commons:通用抽象


服务发现,负载平衡和断路器之类的模式将它们带到一个通用的抽象层,可以由所有Spring Cloud客户端使用,而与实现无关(例如,使用Eureka或Consul进行的发现) )。

3.1 @EnableDiscoveryClient

Spring Cloud Commons提供了@EnableDiscoveryClient批注。这将寻找META-INF/spring.factoriesDiscoveryClient接口的实现。Discovery Client的实现在org.springframework.cloud.client.discovery.EnableDiscoveryClient键下将配置类添加到spring.factoriesDiscoveryClient实现的示例包括Spring Cloud Netflix EurekaSpring Cloud Consul发现Spring Cloud Zookeeper发现

默认情况下,DiscoveryClient的实现会自动将本地Spring Boot服务器注册到远程发现服务器。可以通过在@EnableDiscoveryClient中设置autoRegister=false来禁用此行为。

不再需要@EnableDiscoveryClient。您可以在类路径上放置DiscoveryClient实现,以使Spring Boot应用程序向服务发现服务器注册。

3.1.1健康指标

公用创建了Spring Boot HealthIndicatorDiscoveryClient实现可以通过实现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.2订购DiscoveryClient实例

DiscoveryClient接口扩展了Ordered。当使用多个发现客户端时,这很有用,因为它允许您定义返回的发现客户端的顺序,类似于如何订购由Spring应用程序加载的beans。默认情况下,任何DiscoveryClient的顺序都设置为0。如果要为自定义DiscoveryClient实现设置不同的顺序,则只需覆盖getOrder()方法,以便它返回适合您的设置的值。除此之外,您可以使用属性来设置Spring Cloud提供的DiscoveryClient实现的顺序,其中包括ConsulDiscoveryClientEurekaDiscoveryClientZookeeperDiscoveryClient。为此,您只需要将spring.cloud.{clientIdentifier}.discovery.order(对于Eureka,则为eureka.client.order)属性设置为所需的值。

3.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实现。

  • ZookeeperRegistrationZookeeperServiceRegistry一起使用
  • EurekaRegistrationEurekaServiceRegistry一起使用
  • ConsulRegistrationConsulServiceRegistry一起使用

如果您使用的是ServiceRegistry接口,则将需要为使用的ServiceRegistry实现传递正确的Registry实现。

3.2.1 ServiceRegistry自动注册

默认情况下,ServiceRegistry实现会自动注册正在运行的服务。要禁用该行为,可以设置:* @EnableDiscoveryClient(autoRegister=false)以永久禁用自动注册。* spring.cloud.service-registry.auto-registration.enabled=false通过配置禁用行为。

ServiceRegistry自动注册Events

服务自动注册时将触发两个事件。注册服务之前会触发名为InstancePreRegisteredEvent的第一个事件。注册服务后,将触发名为InstanceRegisteredEvent的第二个事件。您可以注册ApplicationListener,以收听和响应这些事件。

如果将spring.cloud.service-registry.auto-registration.enabled设置为false,则不会触发这些事件。

3.2.2服务注册表执行器端点

Spring Cloud Commons提供了一个/service-registry执行器端点。该端点依赖于Spring应用程序上下文中的Registration bean。使用GET调用/service-registry会返回Registration的状态。对具有JSON正文的同一终结点使用POST会将当前Registration的状态更改为新值。JSON正文必须包含带有首选值的status字段。请参阅更新状态时用于允许值的ServiceRegistry实现的文档以及为状态返回的值。例如,Eureka的受支持状态为UPDOWNOUT_OF_SERVICEUNKNOWN

3.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需要使用虚拟主机名(即服务名,而不是主机名)。Ribbon客户端用于创建完整的物理地址。有关如何设置RestTemplate的详细信息,请参见RibbonAutoConfiguration

重要

为了使用负载均衡的RestTemplate,您需要在类路径中具有负载均衡器实现。推荐的实现是BlockingLoadBalancerClient-添加org.springframework.cloud:spring-cloud-loadbalancer以便使用它。RibbonLoadBalancerClient也可以使用,但是目前正在维护中,我们不建议将其添加到新项目中。

如果要使用BlockingLoadBalancerClient,请确保项目类路径中没有RibbonLoadBalancerClient,因为向后兼容的原因,默认情况下将使用它。

3.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需要使用虚拟主机名(即服务名,而不是主机名)。Ribbon客户端用于创建完整的物理地址。

重要

如果要使用@LoadBalanced WebClient.Builder,则需要在类路径中有一个loadbalancer实现。建议您将org.springframework.cloud:spring-cloud-loadbalancer依赖项添加到项目中。然后,将在下面使用ReactiveLoadBalancer。或者,此功能也可以在spring-cloud-starter-netflix-ribbon上使用,但是该请求将由后台的非响应LoadBalancerClient处理。此外,spring-cloud-starter-netflix-ribbon已经处于维护模式,因此我们不建议您将其添加到新项目中。

在下面使用的ReactorLoadBalancer支持缓存。如果检测到cacheManager,将使用ServiceInstanceSupplier的缓存版本。如果没有,我们将从发现服务中检索实例,而不进行缓存。如果您使用ReactiveLoadBalancer,建议您在项目中启用缓存

3.4.1重试失败的请求

可以配置负载均衡的RestTemplate以重试失败的请求。默认情况下,禁用此逻辑。您可以通过在应用程序的类路径中添加Spring重试来启用它。负载平衡的RestTemplate遵循与重试失败的请求有关的某些Ribbon配置值。您可以使用client.ribbon.MaxAutoRetriesclient.ribbon.MaxAutoRetriesNextServerclient.ribbon.OkToRetryOnAllOperations属性。如果要通过对类路径使用Spring重试来禁用重试逻辑,则可以设置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...
}
}};
}
};
}

}

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("https://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

3.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);
}

}

3.7 Spring WebFlux WebClient作为负载均衡器客户端

3.7.1 Spring具有响应式负载均衡器的WebFlux WebClient

可以将WebClient配置为使用ReactiveLoadBalancer。如果将org.springframework.cloud:spring-cloud-loadbalancer添加到项目中,并且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需要使用虚拟主机名(即服务名,而不是主机名)。ReactorLoadBalancerClient用于创建完整的物理地址。

3.7.2 Spring WebFlux WebClient,带有非反应式负载均衡器客户端

如果您的项目中没有org.springframework.cloud:spring-cloud-loadbalancer,但是确实有spring-cloud-starter-netflix-ribbon,则仍可以将WebClientLoadBalancerClient结合使用。如果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与电抗性负载平衡器一起 使用。

3.7.3传递自己的Load-Balancer客户端配置

您还可以使用@LoadBalancerClient批注传递您自己的负载平衡器客户端配置,并传递负载平衡器客户端的名称和配置类,如下所示:

@Configuration @LoadBalancerClient(value = “stores”, configuration = StoresLoadBalancerClientConfiguration.class) public class MyConfiguration {

_@Bean_
_@LoadBalanced_
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}

}

也可以通过@LoadBalancerClients注释将多个配置(对于一个以上的负载均衡器客户端)一起传递,如下所示:

@Configuration @LoadBalancerClients({@LoadBalancerClient(value = “stores”, configuration = StoresLoadBalancerClientConfiguration.class), @LoadBalancerClient(value = “customers”, configuration = CustomersLoadBalancerClientConfiguration.class)}) public class MyConfiguration {

_@Bean_
_@LoadBalanced_
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}

}

3.8忽略网络接口

有时,忽略某些命名的网络接口很有用,以便可以将它们从服务发现注册中排除(例如,在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()

Copyright © 2002 - 2024 VMware, Inc. All Rights Reserved.

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.