3. Spring Cloud Commons:Common Abstractions

服务发现,负载平衡和断路器等模式适用于所有 Spring Cloud clients 可以使用的 common 抽象层,与 implementation 无关(对于 example,发现 Eureka 或 Consul)。

3.1 @EnableDiscoveryClient

Spring Cloud Commons 提供@EnableDiscoveryClient annotation。这将使用META-INF/spring.factories查找DiscoveryClient接口的 implementations。 _ Discovery Client 的实现在org.springframework.cloud.client.discovery.EnableDiscoveryClient key 下将 configuration class 添加到spring.factoriesDiscoveryClient __mplement 的示例包括Spring Cloud Netflix EurekaSpring Cloud Consul DiscoverySpring Cloud Zookeeper Discovery

默认情况下,DiscoveryClient auto-register 本地 Spring Boot 服务器与 remote 发现服务器的实现。可以通过在@EnableDiscoveryClient中设置autoRegister=false来禁用此行为。

不再需要@EnableDiscoveryClient。您可以在 classpath 上放置DiscoveryClient implementation,以使 Spring Boot application 向服务发现服务器注册。

3.1.1 健康指标

Commons _创建一个 Spring Boot HealthIndicatorDiscoveryClient __mplement 可以通过实现DiscoveryHealthIndicator来参与。要禁用复合HealthIndicator,请设置spring.cloud.discovery.client.composite-indicator.enabled=false。基于DiscoveryClient的通用HealthIndicator是 auto-configured(DiscoveryClientHealthIndicator)。要禁用它,请设置spring.cloud.discovery.client.health-indicator.enabled=false。要禁用DiscoveryClientHealthIndicator的描述字段,请设置spring.cloud.discovery.client.health-indicator.include-description=false。否则,它可能会卷起HealthIndicator卷起HealthIndicator

3.2 ServiceRegistry

Commons _now 提供ServiceRegistry接口,提供register(Registration)deregister(Registration)等方法,让您提供自定义注册服务。 Registration是标记界面。

以下 example 显示正在使用的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 implementation 都有自己的Registry implementation。

  • ZookeeperRegistrationZookeeperServiceRegistry一起使用

  • EurekaRegistrationEurekaServiceRegistry一起使用

  • ConsulRegistrationConsulServiceRegistry一起使用

如果您使用ServiceRegistry接口,则需要为正在使用的ServiceRegistry implementation 传递正确的Registry implementation。

3.2.1 ServiceRegistry Auto-Registration

默认情况下,ServiceRegistry implementation auto-registers _运行服务。要禁用该行为,您可以设置:* @EnableDiscoveryClient(autoRegister=false)永久禁用 auto-registration。 * spring.cloud.service-registry.auto-registration.enabled=false通过 configuration 禁用行为。

ServiceRegistry Auto-Registration Events

服务 auto-registers 时会触发两个 event。第一个 event,名为InstancePreRegisteredEvent,在注册服务之前被触发。第二个 event,名为InstanceRegisteredEvent,在注册服务后触发。您可以注册ApplicationListener(s)来收听并对这些 events 做出反应。

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

3.2.2 Service Registry Actuator 端点

Spring Cloud Commons 提供/service-registry actuator 端点。此端点依赖于 Spring Application Context 中的Registration bean。使用 GET 调用/service-registry将返回Registration的状态。将 POST 用于具有 JSON 主体的同一端点会将当前Registration的状态更改为新的 value。 JSON 主体必须包含status字段和首选 value。更新状态和为状态返回的值时,请参阅用于允许值的ServiceRegistry implementation 的文档。例如,Eureka 支持的状态是UPDOWNOUT_OF_SERVICEUNKNOWN

3.3 Spring RestTemplate 作为负载均衡器 Client

RestTemplate可以自动配置为使用 ribbon。要创建 load-balanced 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;
    }
}

不再通过 auto-configuration 创建RestTemplate bean。单个 applications 必须创建它。

URI 需要使用虚拟 host name(即服务 name,而不是 host name)。 Ribbon client 用于创建完整的物理地址。有关如何设置RestTemplate的详细信息,请参阅RibbonAutoConfiguration

3.4 Spring WebClient 作为负载均衡器 Client

WebClient可以自动配置为使用LoadBalancerClient。要创建 load-balanced 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 需要使用虚拟 host name(即服务 name,而不是 host name)。 Ribbon client 用于创建完整的物理地址。

3.4.1 重试失败的请求

可以将 load-balanced RestTemplate配置为重试失败的请求。默认情况下,禁用此逻辑。您可以通过将Spring 重试添加到 application 的 classpath 来启用它。 load-balanced RestTemplate尊重与重试失败请求相关的一些 Ribbon configuration 值。您可以使用client.ribbon.MaxAutoRetriesclient.ribbon.MaxAutoRetriesNextServerclient.ribbon.OkToRetryOnAllOperations properties。如果要在 classpath 上使用 Spring Retry 禁用重试逻辑,可以设置spring.cloud.loadbalancer.retry.enabled=false。有关这些 properties 的说明,请参阅Ribbon 文档

如果要在重试中实现BackOffPolicy,则需要创建类型的 bean 并覆盖createBackOffPolicy方法:

@Configuration
public class MyConfiguration {
    @Bean
    LoadBalancedRetryFactory retryFactory() {
        return new LoadBalancedRetryFactory() {
            @Override
            public BackOffPolicy createBackOffPolicy(String service) {
        		return new ExponentialBackOffPolicy();
        	}
        };
    }
}

前面示例中的client应替换为 Ribbon client 的 name。

如果要在重试功能中添加一个或多个RetryListener __mplement,则需要创建类型的 bean 并_返回要用于给定服务的RetryListener array,如下面的示例所示:

@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 objects

如果你想要一个不是 load-balanced 的RestTemplate,创建一个RestTemplate bean 并 inject 它。要访问 load-balanced RestTemplate,请在创建@Bean时使用@LoadBalanced限定符,如下面的 example 所示:\

@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);
    }
}

注意在前面的 example 中的 plain RestTemplate声明上使用@Primary annotation 来消除不合格的@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 Spring WebFlux WebClient 作为负载均衡器 Client

WebClient可以配置为使用LoadBalancerClient。如果spring-webflux在 classpath 上,LoadBalancerExchangeFilterFunction是 auto-configured。以下 example 显示了如何配置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 需要使用虚拟 host name(即服务 name,而不是 host name)。 LoadBalancerClient用于创建完整的物理地址。

3.7 忽略网络接口

有时,忽略某些命名的网络接口以便可以从 Service Discovery 注册中排除它们(例如,在 Docker 容器中运行时)。可以设置正则表达式列表以使所需的网络接口被忽略。以下 configuration 忽略docker0接口和所有以veth开头的接口:

application.yml.

spring:
  cloud:
    inetutils:
      ignoredInterfaces:
        - docker0
        - veth.*

您还可以使用正则表达式列表强制仅使用指定的网络地址,如下面的示例所示:

bootstrap.yml.

spring:
  cloud:
    inetutils:
      preferredNetworks:
        - 192.168
        - 10.0

您还可以强制仅使用 site-local 地址,如下例所示:.application.yml

spring:
  cloud:
    inetutils:
      useOnlySiteLocalInterfaces: true

有关 site-local 地址构成的更多详细信息,请参阅Inet4Address.html.isSiteLocalAddress()

3.8 HTTP Client Factories

Spring Cloud Commons _provides beans for creating Apache HTTP clients(ApacheHttpClientFactory)和 OK HTTP clients(OkHttpClientFactory)。只有在 classpath 上有 OK HTTP jar 时才会创建OkHttpClientFactory bean。另外,Spring Cloud Commons _provides beans 用于创建两个 clients 使用的连接_manage:ApacheHttpClientConnectionManagerFactory用于 Apache HTTP client,OkHttpClientConnectionPoolFactory用于 OK HTTP client。如果您想自定义在下游项目中创建 HTTP clients 的方式,您可以提供自己的_bemplementation beans。此外,如果提供HttpClientBuilderOkHttpClient.Builder类型的 bean,则默认工厂将使用这些构建器作为返回到下游项目的构建器的基础。您还可以通过将spring.cloud.httpclientfactories.apache.enabledspring.cloud.httpclientfactories.ok.enabled设置为false来禁用这些 beans 的创建。

3.9 已启用 Features

Spring Cloud Commons 提供/features actuator 端点。此端点返回 classpath 上可用的 features 以及它们是否已启用。返回的信息包括 feature 类型,name,version 和 vendor。

3.9.1 特征类型

有两种类型的'features':抽象和命名。

抽象 features 是 features,其中定义了接口或抽象 class,并且创建了 implementation,例如DiscoveryClientLoadBalancerClientLockService。 abstract class 或 interface 用于在 context 中查找该类型的 bean。显示的 version 是bean.getClass().getPackage().getImplementationVersion()

命名 features 是 features 没有他们实现的特定 class,例如“Circuit Breaker”,“API Gateway”,“ Spring Cloud Bus”等。这些 features 需要 name 和 bean 类型。

3.9.2 声明 features

任何模块都可以声明任意数量的HasFeature beans,如以下示例所示:

@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();
}

这些 beans 中的每一个都应该进行适当的保护@Configuration