2. Spring Cloud Commons: Common Abstractions

诸如服务发现、负载均衡和断路器等模式可被抽象为一个通用层,供所有 Spring Cloud 客户端使用,且与具体实现(例如使用 Eureka 或 Consul 进行服务发现)无关。spring-doc.cadn.net.cn

将以下 java 开发 Spring 框架 英文网站的html内容翻译成中文,保持html结构和标签名称不变,结果以json结构返回,

2.1. The @EnableDiscoveryClient Annotationspring-doc.cadn.net.cn

Spring Cloud Commons 提供了 @EnableDiscoveryClient 注解。该注解用于查找实现了 DiscoveryClientReactiveDiscoveryClient 接口的实现类,并带有 META-INF/spring.factories 注解。发现客户端的实现类会将一个配置类添加到 spring.factories 中,键为 org.springframework.cloud.client.discovery.EnableDiscoveryClientDiscoveryClient 的示例实现包括 Spring Cloud Netflix EurekaSpring Cloud Consul DiscoverySpring Cloud Zookeeper Discoveryspring-doc.cadn.net.cn

Spring Cloud 将默认提供阻塞式和响应式服务发现客户端。您可以通过设置 spring.cloud.discovery.blocking.enabled=falsespring.cloud.discovery.reactive.enabled=false 轻松禁用阻塞式和/或响应式客户端。若要完全禁用服务发现功能,只需设置 spring.cloud.discovery.enabled=false 即可。spring-doc.cadn.net.cn

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

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

2.1.1. 健康指标

Commons 自动配置以下 Spring Boot 健康指标。spring-doc.cadn.net.cn

DiscoveryClientHealthIndicator

此健康指标基于当前注册的 DiscoveryClient 个实现。spring-doc.cadn.net.cn

  • 要完全禁用,请设置 spring.cloud.discovery.client.health-indicator.enabled=falsespring-doc.cadn.net.cn

  • 要禁用描述字段,请将 spring.cloud.discovery.client.health-indicator.include-description=false 设置为该字段。否则,它可能会作为汇总的 descriptionHealthIndicator 传播出去。spring-doc.cadn.net.cn

  • 要禁用服务检索,请将 spring.cloud.discovery.client.health-indicator.use-services-query=false 设置为禁用状态。
    默认情况下,该指示器会调用客户端的 getServices 方法。在注册服务数量较多的部署环境中,每次检查时都检索所有服务可能过于昂贵。这将跳过服务检索步骤,转而使用客户端的 probe 方法。spring-doc.cadn.net.cn

DiscoveryCompositeHealthContributor

此复合健康指标基于所有已注册的 DiscoveryHealthIndicator 个 Bean。要禁用它,请设置 spring.cloud.discovery.client.composite-indicator.enabled=falsespring-doc.cadn.net.cn

2.1.2. 排序DiscoveryClient个实例

DiscoveryClient 接口扩展 Ordered。这在使用多个发现客户端时非常有用,因为它允许您定义返回的发现客户端的顺序,类似于您可以对 Spring 应用程序加载的 Bean 进行排序的方式。默认情况下,任何 DiscoveryClient 的顺序设置为 0。如果您希望为自定义 DiscoveryClient 实现设置不同的顺序,只需重写 getOrder() 方法,使其返回适用于您环境的值即可。除此之外,您还可以通过属性来设置由 Spring Cloud 提供的 DiscoveryClient 实现的顺序,例如 ConsulDiscoveryClientEurekaDiscoveryClientZookeeperDiscoveryClient。要实现此目的,您只需将 spring.cloud.{clientIdentifier}.discovery.order(或针对 Eureka 的 eureka.client.order)属性设置为所需的值。spring-doc.cadn.net.cn

2.1.3. 简单发现客户端

如果类路径中没有基于服务注册中心的 DiscoveryClient,则将使用 SimpleDiscoveryClient 实例,该实例通过属性获取服务和实例的相关信息。spring-doc.cadn.net.cn

可用实例的信息应通过以下格式的属性传递:spring.cloud.discovery.client.simple.instances.service1[0].uri=http://s11:8080,其中 spring.cloud.discovery.client.simple.instances 是公共前缀,service1 表示所涉及服务的ID,[0] 表示实例的索引编号(如示例所示,索引从 0 开始),而 uri 的值即为该实例实际可用的URI。spring-doc.cadn.net.cn

2.2. 服务注册中心

Commons 现在提供了一个 ServiceRegistry 接口,该接口提供了诸如 register(Registration)deregister(Registration) 等方法,使您能够提供自定义注册的服务。Registration 是一个标记接口。spring-doc.cadn.net.cn

以下示例展示了 ServiceRegistry 的用法:spring-doc.cadn.net.cn

@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 实现。spring-doc.cadn.net.cn

如果您正在使用 ServiceRegistry 接口,则需要为所使用的 ServiceRegistry 实现传递正确的 Registry 实现。spring-doc.cadn.net.cn

2.2.1. ServiceRegistry 自动注册

默认情况下,ServiceRegistry 实现会自动注册运行中的服务。要禁用此行为,您可以设置:spring-doc.cadn.net.cn

  • @EnableDiscoveryClient(autoRegister=false) 以永久禁用自动注册。
  • spring.cloud.service-registry.auto-registration.enabled=false 通过配置禁用该行为。

spring-doc.cadn.net.cn

服务注册表自动注册事件

当服务自动注册时,会触发两个事件。第一个事件,称为InstancePreRegisteredEvent,在服务注册前触发。第二个事件,称为InstanceRegisteredEvent,在服务注册后触发。您可以注册一个或多个ApplicationListener(监听器)来监听并响应这些事件。spring-doc.cadn.net.cn

这些事件在将 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 支持的状态包括 UPDOWNOUT_OF_SERVICEUNKNOWNspring-doc.cadn.net.cn

2.3. 使用 Spring RestTemplate 实现负载均衡客户端

您可以配置一个 RestTemplate 以使用负载均衡客户端。要创建一个负载均衡的 RestTemplate,请创建一个 RestTemplate @Bean 并使用 @LoadBalanced 注解限定符,如下例所示:spring-doc.cadn.net.cn

@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 RestTemplate bean is no longer created through auto-configuration.spring-doc.cadn.net.cn

Individual applications must create it.spring-doc.cadn.net.cn

URI 需要使用虚拟主机名(即服务名称,而不是主机名称)。<br>BlockingLoadBalancerClient 用于创建完整的物理地址。spring-doc.cadn.net.cn

要使用负载均衡的RestTemplate,您需要在类路径中包含一个负载均衡器实现。

spring-doc.cadn.net.cn

请将Spring Cloud LoadBalancer starter添加到您的项目中以使用它。spring-doc.cadn.net.cn

2.4. Spring WebClient作为负载均衡客户端

您可以将 WebClient 配置为自动使用负载均衡客户端。要创建一个负载均衡的 WebClient,请创建一个 WebClient.Builder @Bean 并使用 @LoadBalanced 注解限定符,如下所示:spring-doc.cadn.net.cn

@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 用于创建完整的物理地址。spring-doc.cadn.net.cn

如果您想使用@LoadBalanced WebClient.Builder,您需要在类路径中有负载均衡器实现。我们建议您向项目中添加Spring Cloud LoadBalancerStarters。然后,在底层会使用ReactiveLoadBalancer

2.4.1. 失败请求重试

负载均衡的RestTemplate可以配置为重试失败的请求。默认情况下,此逻辑是禁用的。对于非响应式版本(带有RestTemplate),您可以通过将Spring Retry添加到应用程序的类路径来启用它。对于响应式版本(带有WebTestClient), you need to set `spring.cloud.loadbalancer.retry.enabled=truespring-doc.cadn.net.cn

如果您希望禁用 Spring Retry 或 Reactive Retry 的重试逻辑(当类路径中存在这些依赖时),可以设置 spring.cloud.loadbalancer.retry.enabled=falsespring-doc.cadn.net.cn

对于非响应式实现,如果您希望在重试中实现 BackOffPolicy,则需要创建一个类型为 LoadBalancedRetryFactory 的 Bean,并重写 createBackOffPolicy() 方法。spring-doc.cadn.net.cn

对于响应式实现,您只需通过将 spring.cloud.loadbalancer.retry.backoff.enabled 设置为 false 来启用它。spring-doc.cadn.net.cn

您可以设置:spring-doc.cadn.net.cn

  • spring.cloud.loadbalancer.retry.maxRetriesOnSameServiceInstance - 表示应在同一 ServiceInstance(针对每个选定实例分别计数)上重试请求的次数。spring-doc.cadn.net.cn

  • spring.cloud.loadbalancer.retry.maxRetriesOnNextServiceInstance - 表示应重新尝试请求的次数,该请求是新选定的 ServiceInstancespring-doc.cadn.net.cn

  • spring.cloud.loadbalancer.retry.retryableStatusCodes - 在其上始终重试失败请求的状态码。spring-doc.cadn.net.cn

对于响应式实现,您可以另外设置:
- spring.cloud.loadbalancer.retry.backoff.minBackoff - 设置最小退避时间(默认为5毫秒)
- spring.cloud.loadbalancer.retry.backoff.maxBackoff - 设置最大退避时间(默认为毫秒的最大长值)
- spring.cloud.loadbalancer.retry.backoff.jitter - 设置用于计算每次调用的实际退避时间的抖动(默认为0.5)。spring-doc.cadn.net.cn

对于响应式实现,您还可以实现自己的 LoadBalancerRetryPolicy,以对负载均衡调用的重试过程进行更细致的控制。spring-doc.cadn.net.cn

单个负载均衡客户端可单独配置,其属性与上文所述相同,但前缀为 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 数组,如下例所示:spring-doc.cadn.net.cn

@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 限定符,如下例所示:spring-doc.cadn.net.cn

@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 限定符,如下例所示:spring-doc.cadn.net.cn

@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 配置一起使用,如各主题所述:spring-doc.cadn.net.cn

2.7.1. Spring WebFlux WebClientReactorLoadBalancerExchangeFilterFunction

您可以配置WebClient以使用ReactiveLoadBalancer
如果将Spring Cloud LoadBalancer starter添加到项目中,且spring-webflux在类路径上,则自动配置ReactorLoadBalancerExchangeFilterFunction
以下示例显示了如何配置WebClient以使用响应式负载均衡器:spring-doc.cadn.net.cn

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 需要使用虚拟主机名(即服务名称,而非主机名)。spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

ReactorLoadBalancer 用于创建完整的物理地址。spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

2.7.2. 使用非响应式负载均衡客户端的 Spring WebFlux WebClient

如果 spring-webflux 在类路径中,则会自动配置 LoadBalancerExchangeFilterFunction。不过请注意,其底层使用的是非响应式客户端。以下示例展示了如何配置 WebClient 以使用负载均衡器:spring-doc.cadn.net.cn

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 需要使用虚拟主机名(即服务名称,而非主机名)。spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

LoadBalancerClient 用于创建完整的物理地址。spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

警告:此方法现已弃用。
我们建议您改用 WebFlux 与响应式负载均衡器spring-doc.cadn.net.cn

2.8. 忽略网络接口

有时,忽略某些命名的网络接口会很有用,以便将它们从服务发现注册中排除(例如,在 Docker 容器中运行时)。可以通过设置正则表达式列表,来指定需要被忽略的网络接口。以下配置会忽略 docker0 接口以及所有以 veth 开头的接口:spring-doc.cadn.net.cn

示例 2. application.yml
spring:
  cloud:
    inetutils:
      ignoredInterfaces:
        - docker0
        - veth.*

您还可以通过使用正则表达式列表强制仅使用指定的网络地址,如下例所示:spring-doc.cadn.net.cn

示例3. bootstrap.yml
spring:
  cloud:
    inetutils:
      preferredNetworks:
        - 192.168
        - 10.0

你也可以强制仅使用本地站点地址,如下例所示:spring-doc.cadn.net.cn

示例 4. application.yml
spring:
  cloud:
    inetutils:
      useOnlySiteLocalInterfaces: true

有关什么是站点本地地址的更多详情,请参见 Inet4Address.html.isSiteLocalAddress()spring-doc.cadn.net.cn

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 的自定义实现。
另外,如果您提供了类型为 HttpClientBuilderOkHttpClient.Builder 的 Bean,则默认工厂会使用这些构建器作为向下游项目返回的构建器的基础。
您还可以通过将 spring.cloud.httpclientfactories.apache.enabledspring.cloud.httpclientfactories.ok.enabled 设置为 false 来禁用这些 Bean 的创建。spring-doc.cadn.net.cn

2.10. 已启用的功能

Spring Cloud Commons 提供了一个 /features 操作端点。此端点返回类路径上可用的功能及其是否已启用的信息。返回的信息包括功能类型、名称、版本和提供商。spring-doc.cadn.net.cn

2.10.1. 功能类型

有两种类型的‘特性’:抽象特性和命名特性。spring-doc.cadn.net.cn

抽象功能是指在接口或抽象类中定义的功能,其具体实现由创建的类提供,例如 DiscoveryClientLoadBalancerClientLockService。抽象类或接口用于在上下文中查找该类型的 Bean。当前显示的版本是 bean.getClass().getPackage().getImplementationVersion()spring-doc.cadn.net.cn

命名功能是指那些没有特定实现类的功能。这些功能包括“熔断器”、“API 网关”、“Spring Cloud Bus”等。这些功能需要一个名称和一个 Bean 类型。spring-doc.cadn.net.cn

2.10.2. 声明功能

任何模块都可以声明任意数量的HasFeature个 bean,如下面的示例所示:spring-doc.cadn.net.cn

@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 里。spring-doc.cadn.net.cn

2.11. Spring Cloud 兼容性验证

由于一些用户在设置 Spring Cloud 应用程序时遇到问题,我们决定添加兼容性验证机制。 它将在当前设置与 Spring Cloud 要求不兼容时中断,同时显示报告,显示具体出错内容。spring-doc.cadn.net.cn

当前正在验证Spring Boot版本已添加到类路径。spring-doc.cadn.net.cn

***************************
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-doc.cadn.net.cn