欢迎访问shiker.tech

请允许在我们的网站上展示广告

您似乎使用了广告拦截器,请关闭广告拦截器。我们的网站依靠广告获取资金。

【译文】云原生应用spring-cloud介绍
(last modified Jun 26, 2023, 12:32 PM )
by
侧边栏壁纸
  • 累计撰写 178 篇文章
  • 累计创建 62 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

【译文】云原生应用spring-cloud介绍

橙序员
2022-08-21 / 0 评论 / 0 点赞 / 590 阅读 / 14,966 字 / 正在检测百度是否收录... 正在检测必应是否收录...
文章摘要(AI生成)

云原生是一种应用程序开发风格,它鼓励在持续交付和价值驱动开发领域轻松采用最佳实践。一个相关的学科是构建12 要素应用程序,其中开发实践与交付和运营目标保持一致——例如,通过使用声明式编程以及管理和监控。Spring Cloud 以多种特定方式促进了这些开发风格。起点是分布式系统中的所有组件都需要轻松

云原生是一种应用程序开发风格,它鼓励在持续交付和价值驱动开发领域轻松采用最佳实践。一个相关的学科是构建12 要素应用程序,其中开发实践与交付和运营目标保持一致——例如,通过使用声明式编程以及管理和监控。Spring Cloud 以多种特定方式促进了这些开发风格。起点是分布式系统中的所有组件都需要轻松访问的一组特性。

Spring Boot涵盖了其中许多功能,Spring Cloud 在此基础上构建。Spring Cloud 以两个库的形式提供了更多功能:Spring Cloud Context 和 Spring Cloud Commons。ApplicationContextSpring Cloud Context 为Spring Cloud 应用程序(引导上下文、加密、刷新范围和环境端点)提供实用程序和特殊服务。Spring Cloud Commons 是一组抽象和通用类,用于不同的 Spring Cloud 实现(例如 Spring Cloud Netflix 和 Spring Cloud Consul)。

如果由于“非法密钥大小”而出现异常并且使用 Sun 的 JDK,则需要安装 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files。有关更多信息,请参阅以下链接:

将文件解压缩到您使用的 JRE/JDK x64/x86 版本的 JDK/jre/lib/security 文件夹中。

Spring Cloud 在非限制性 Apache 2.0 许可下发布。如果您想对文档的这一部分做出贡献或发现错误,您可以在 {docslink}[github] 上找到该项目的源代码和问题跟踪器。

1. Spring Cloud Context:应用上下文服务

Spring Boot 对如何使用 Spring 构建应用程序有自己的看法。例如,它具有用于常见配置文件的常规位置,并具有用于常见管理和监视任务的端点。Spring Cloud 建立在此之上,并添加了系统中许多组件会使用或偶尔需要的一些功能。

1.1。引导应用程序上下文

Spring Cloud 应用程序通过创建“引导”上下文来运行,该上下文是主应用程序的父上下文。此上下文负责从外部源加载配置属性并解密本地外部配置文件中的属性。这两个上下文共享一个Environment,它是任何 Spring 应用程序的外部属性的来源。默认情况下,bootstrap.properties以高优先级添加引导属性(不是在引导阶段加载的属性),因此它们不能被本地配置覆盖。

引导上下文使用与主应用程序上下文不同的约定来定位外部配置。代替application.yml(或.properties),您可以使用bootstrap.yml,保持引导程序和主上下文的外部配置很好地分开。以下清单显示了一个示例:

示例 1.bootstrap.yml

spring:
  application:
    name: foo
  cloud:
    config:
      uri: ${SPRING_CONFIG_URI:http://localhost:8888}

如果您的应用程序需要来自服务器的任何特定于应用程序的配置,最好设置spring.application.name(inbootstrap.ymlapplication.yml)。要将该属性spring.application.name用作应用程序的上下文 ID,您必须将其设置为bootstrap.[properties | yml].

如果要检索特定的配置文件配置,还应该spring.profiles.activebootstrap.[properties | yml].

spring.cloud.bootstrap.enabled=false您可以通过设置(例如,在系统属性中)完全禁用引导过程。

1.2. 应用程序上下文层次结构

SpringApplication如果您从或构建应用程序上下文SpringApplicationBuilder,则 Bootstrap 上下文将作为父级添加到该上下文中。Spring 的一个特性是子上下文从其父上下文继承属性源和配置文件,因此与在没有 Spring Cloud Config 的情况下构建相同的上下文相比,“主”应用程序上下文包含额外的属性源。其他属性来源是:

  • “bootstrap”:如果PropertySourceLocators在 bootstrap 上下文中找到任何属性,并且它们具有非空属性,CompositePropertySource则以高优先级出现一个可选项。一个例子是来自 Spring Cloud Config Server 的属性。有关如何自定义此属性源的内容,请参阅“自定义 Bootstrap 属性源”。
  • “applicationConfig: [classpath:bootstrap.yml]”(以及相关文件,如果 Spring 配置文件处于活动状态):如果您有bootstrap.yml(或.properties),则这些属性用于配置引导上下文。然后在设置其父级时将它们添加到子级上下文中。它们的优先级低于application.yml(or .properties) 和任何其他作为创建 Spring Boot 应用程序过程的正常部分添加到子级的属性源。有关如何自定义这些属性源的内容,请参阅“更改引导属性的位置”。

由于属性源的排序规则,“引导”条目优先。但是,请注意,这些不包含来自 的任何数据,这些数据的bootstrap.yml优先级非常低,但可用于设置默认值。

您可以通过设置您创建的任何内容的父上下文来扩展上下文层次结构ApplicationContext——例如,通过使用其自己的接口或使用SpringApplicationBuilder便捷方法(parent()child()sibling()。引导上下文是您自己创建的最高级祖先的父级。层次结构中的每个上下文都有自己的“引导”(可能为空)属性源,以避免无意中将值从父级提升到其子级。如果有一个配置服务器,层次结构中的每个上下文也可以(原则上)有不同的spring.application.name因此,一个不同的远程属性源。正常的 Spring 应用程序上下文行为规则适用于属性解析:子上下文中的属性覆盖父上下文中的属性,按名称和属性源名称。(如果子级具有与父级同名的属性源,则父级的值不包含在子级中)。

请注意,SpringApplicationBuilder允许您在整个层次结构中共享一个Environment,但这不是默认设置。因此,兄弟上下文(特别是)不需要具有相同的配置文件或属性源,即使它们可能与其父级共享共同值。

1.3. 更改引导属性的位置

bootstrap.yml.properties)位置可以通过设置spring.cloud.bootstrap.name(默认值:bootstrap)、spring.cloud.bootstrap.location(默认值:空)或spring.cloud.bootstrap.additional-location(默认值:空)来指定——例如,在系统属性中。

这些属性的行为类似于spring.config.*具有相同名称的变体。spring.cloud.bootstrap.location替换默认位置,仅使用指定的位置。要将位置添加到默认位置列表中,spring.cloud.bootstrap.additional-location可以使用。实际上,它们用于ApplicationContext通过在其Environment. 如果有一个活动的配置文件(来自spring.profiles.active或通过Environment您正在构建的上下文中的 API),该配置文件中的属性也会被加载,与常规 Spring Boot 应用程序中的属性相同 - 例如,来自bootstrap-development.properties配置development文件。

1.4. 覆盖远程属性的值

通过引导上下文添加到应用程序的属性源通常是“远程的”(例如,来自 Spring Cloud Config Server)。默认情况下,它们不能在本地被覆盖。如果您想让您的应用程序使用自己的系统属性或配置文件覆盖远程属性,则远程属性源必须通过设置授予它权限spring.cloud.config.allowOverride=true(在本地设置此设置不起作用)。一旦设置了该标志,两个更细粒度的设置控制远程属性相对于系统属性和应用程序本地配置的位置:

  • spring.cloud.config.overrideNone=true:从任何本地属性源覆盖。
  • spring.cloud.config.overrideSystemProperties=false:只有系统属性、命令行参数和环境变量(而不是本地配置文件)应该覆盖远程设置。

1.5。自定义引导配置

通过将条目添加到/META-INF/spring.factories名为org.springframework.cloud.bootstrap.BootstrapConfiguration. @Configuration这包含用于创建上下文的 Spring 类的逗号分隔列表。可以在此处创建您希望可用于主应用程序上下文以进行自动装配的任何 bean。@Beanstype有一个特殊的合同ApplicationContextInitializer。如果要控制启动顺序,可以用@Order注解标记类(默认顺序为last)。

添加 customBootstrapConfiguration时,请注意不要将您添加的类@ComponentScanned错误地添加到您可能不需要它们的“主”应用程序上下文中。为引导配置类使用单独的包名称,并确保该名称尚未包含在您的@ComponentScan或带@SpringBootApplication注释的配置类中。

引导过程通过将初始化程序注入主SpringApplication实例来结束(这是正常的 Spring Boot 启动顺序,无论它作为独立应用程序运行还是部署在应用程序服务器中)。首先,从 中找到的类创建引导上下文spring.factories。然后,在 main启动之前,所有@Beans的 typeApplicationContextInitializer都被添加到 main中。SpringApplication

1.6. 自定义引导属性源

PropertySourceLocator引导过程添加的外部配置的默认属性源是 Spring Cloud Config Server,但您可以通过将类型的 bean 添加到引导上下文(通过spring.factories)来添加其他源。例如,您可以从不同的服务器或数据库中插入其他属性。

例如,考虑以下自定义定位器:

@Configuration
public class CustomPropertySourceLocator implements PropertySourceLocator {

    @Override
    public PropertySource<?> locate(Environment environment) {
        return new MapPropertySource("customProperty",
                Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended"));
    }

}

传入的EnvironmentApplicationContext即将被创建的那个——换句话说,我们为其提供额外的属性源的那个。它已经有其正常的 Spring Boot 提供的属性源,因此您可以使用它们来定位特定于此的属性源Environment(例如,通过将其键入spring.application.name,就像在默认的 Spring Cloud Config Server 属性源定位器中所做的那样)。

如果您在其中创建包含此类的 jar,然后添加META-INF/spring.factories包含以下设置的 jar,则 将customProperty PropertySource出现在其类路径中包含该 jar 的任何应用程序中:

org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator

1.7. 日志记录配置

bootstrap.[yml | properties]如果您使用 Spring Boot 配置日志设置,如果您希望将此配置应用于所有事件,则应放置此配置。

为了让 Spring Cloud 正确初始化日志配置,您不能使用自定义前缀。例如,custom.loggin.logpath在初始化日志系统时,Spring Cloud 无法识别 using。

1.8. 环境变化

应用程序以几种标准方式监听EnvironmentChangeEvent并响应变化(ApplicationListeners可以像@Beans正常方式一样添加额外的)。当EnvironmentChangeEvent观察到 an 时,它有一个已更改的键值列表,应用程序使用这些键值来:

  • 重新绑定@ConfigurationProperties上下文中的任何 bean。
  • 为 中的任何属性设置记录器级别logging.level.*

请注意,默认情况下,Spring Cloud Config Client 不会轮询Environment. 通常,我们不建议使用这种方法来检测更改(尽管您可以使用 @Scheduled注释进行设置)。如果您有一个横向扩展的客户端应用程序,最好将 广播EnvironmentChangeEvent到所有实例,而不是让它们轮询更改(例如,通过使用Spring Cloud Bus)。

涵盖了一EnvironmentChangeEvent大类刷新用例,只要您可以实际更改Environment并发布事件即可。请注意,这些 API 是公共的,并且是核心 Spring 的一部分)。您可以通过访问端点(标准 Spring Boot Actuator 功能)来验证更改是否绑定到@ConfigurationPropertiesbean 。/configprops例如,aDataSource可以maxPoolSize在运行时更改(Spring Boot 默认DataSource创建的是@ConfigurationPropertiesbean)并动态增加容量。重新绑定@ConfigurationProperties不涵盖另一大类用例,在这些用例中,您需要对刷新进行更多控制,并且需要对整个ApplicationContext. 为了解决这些问题,我们有@RefreshScope.

1.9。刷新范围

当配置发生变化时,@Bean标记为的 Spring@RefreshScope会得到特殊处理。此功能解决了仅在初始化时才注入其配置的有状态 bean 的问题。例如,如果在DataSource通过 更改数据库 URL 时 a 有打开的连接Environment,您可能希望这些连接的持有者能够完成他们正在做的事情。然后,下一次从池中借用连接时,它会使用新的 URL 获得一个。

有时,甚至可能强制@RefreshScope在某些只能初始化一次的 bean 上应用注释。如果一个 bean 是“不可变的”,你必须在 bean 上注解@RefreshScope或者在属性键下指定类名:spring.cloud.refresh.extra-refreshable.

如果你有一个DataSourcebean HikariDataSource,它不能被刷新。它是 的默认值spring.cloud.refresh.never-refreshableDataSource如果需要刷新,请 选择不同的实现。

刷新作用域 bean 是在使用时(即调用方法时)初始化的惰性代理,作用域充当初始化值的缓存。要强制 bean 在下一个方法调用时重新初始化,您必须使其缓存条目无效。

RefreshScope是上下文中的一个 bean,并且有一个公共refreshAll()方法通过清除目标缓存来刷新范围内的所有 bean。/refresh端点公开此功能(通过 HTTP 或 JMX)。要按名称刷新单个 bean,还有一种refresh(String)方法。

要公开/refresh端点,您需要向应用程序添加以下配置:

management:
  endpoints:
    web:
      exposure:
        include: refresh

@RefreshScope在一个类上工作(技术上)@Configuration,但它可能会导致令人惊讶的行为。例如,这并不意味着@Beans该类中定义的所有内容本身都在@RefreshScope. 具体来说,任何依赖于这些 bean 的东西都不能依赖它们在启动刷新时被更新,除非它本身在@RefreshScope. 在这种情况下,它会在刷新时重建,并重新注入其依赖项。此时,它们会从刷新的@Configuration) 中重新初始化。

1.10。加密和解密

Spring Cloud 有一个Environment预处理器,用于在本地解密属性值。它遵循与 Spring Cloud Config Server 相同的规则,并通过encrypt.*. 因此,您可以使用 形式的加密值{cipher}*,并且只要存在有效密钥,它们就会在主应用程序上下文获取Environment设置之前被解密。要在应用程序中使用加密功能,您需要在类路径中包含 Spring Security RSA(Maven 坐标:)org.springframework.security:spring-security-rsa,并且您还需要 JVM 中的全强度 JCE 扩展。

如果由于“非法密钥大小”而出现异常并且使用 Sun 的 JDK,则需要安装 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files。有关更多信息,请参阅以下链接:

将文件解压缩到您使用的 JRE/JDK x64/x86 版本的 JDK/jre/lib/security 文件夹中。

1.11。端点

对于 Spring Boot Actuator 应用程序,一些额外的管理端点可用。您可以使用:

  • POST/actuator/env更新Environment和重新绑定@ConfigurationProperties和日志级别。要启用此端点,您必须设置management.endpoint.env.post.enabled=true.
  • /actuator/refresh重新加载引导上下文并刷新@RefreshScopebean。
  • /actuator/restart关闭ApplicationContext并重新启动它(默认情况下禁用)。
  • /actuator/pause/actuator/resume用于调用Lifecycle方法(stop()start()ApplicationContext)。

如果禁用/actuator/restart端点,则/actuator/pause/actuator/resume端点也将被禁用,因为它们只是/actuator/restart.

2. Spring Cloud Commons:通用抽象

服务发现、负载平衡和断路器等模式适用于一个公共抽象层,所有 Spring Cloud 客户端都可以使用该抽象层,独立于实现(例如,使用 Eureka 或 Consul 进行发现)。

2.1。@EnableDiscoveryClient注释_

Spring Cloud Commons 提供了@EnableDiscoveryClient注解。这会查找DiscoveryClientReactiveDiscoveryClient接口的实现META-INF/spring.factories。发现客户端的实现在键spring.factories下添加了一个配置类org.springframework.cloud.client.discovery.EnableDiscoveryClient。实现的示例DiscoveryClient包括Spring Cloud Netflix EurekaSpring Cloud Consul DiscoverySpring Cloud Zookeeper Discovery

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

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

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

2.1.1。健康指标

Commons 自动配置以下 Spring Boot 健康指标。

DiscoveryClientHealthIndicator

此运行状况指标基于当前注册的DiscoveryClient实现。

  • 要完全禁用,请设置spring.cloud.discovery.client.health-indicator.enabled=false.
  • 要禁用描述字段,请设置spring.cloud.discovery.client.health-indicator.include-description=false. 否则,它可能会像description卷起来一样冒泡HealthIndicator
  • 要禁用服务检索,请设置spring.cloud.discovery.client.health-indicator.use-services-query=false. 默认情况下,指标调用客户端的getServices方法。在具有许多注册服务的部署中,在每次检查期间检索所有服务的成本可能太高。这将跳过服务检索,而是使用客户端的probe方法。
DiscoveryCompositeHealthContributor

此复合健康指标基于所有已注册的DiscoveryHealthIndicatorbean。要禁用,请设置spring.cloud.discovery.client.composite-indicator.enabled=false.

2.1.2. 订购DiscoveryClient实例

DiscoveryClient接口扩展Ordered。这在使用多个发现客户端时很有用,因为它允许您定义返回的发现客户端的顺序,类似于如何对 Spring 应用程序加载的 bean 进行排序。默认情况下,any 的顺序DiscoveryClient设置为 0。如果您想为您的自定义DiscoveryClient实现设置不同的顺序,您只需要重写该getOrder()方法,以便它返回适合您设置的值。除此之外,您还可以使用属性来设置DiscoveryClient Spring Cloud 等提供的实现的顺序ConsulDiscoveryClientEurekaDiscoveryClient以及 ZookeeperDiscoveryClient. 为此,您只需将 spring.cloud.{clientIdentifier}.discovery.order(或eureka.client.order对于 Eureka)属性设置为所需的值。

2.1.3。简单发现客户端

DiscoveryClient如果类路径中没有服务注册支持,则将SimpleDiscoveryClient 使用使用属性获取服务和实例信息的实例。

有关可用实例的信息应按以下格式通过属性传递: spring.cloud.discovery.client.simple.instances.service1[0].uri=http://s11:8080,其中 spring.cloud.discovery.client.simple.instances是公共前缀,然后service1代表有问题的服务的 ID,而[0]表示实例的索引号(如示例中所示,索引以0) 开头,然后 的值uri是实例可用的实际 URI。

2.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接口,您将需要为您正在使用Registry的实现传递正确的实现ServiceRegistry

2.2.1。ServiceRegistry 自动注册

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

ServiceRegistry 自动注册事件

服务自动注册时将触发两个事件。第一个事件,称为 InstancePreRegisteredEvent,在服务注册之前被触发。第二个事件称为InstanceRegisteredEvent,在服务注册后触发。您可以注册一个 ApplicationListener(s) 来收听这些事件并做出反应。

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

2.2.2。服务注册执行器端点

Spring Cloud Commons 提供了一个/service-registry执行器端点。这个端点依赖于RegistrationSpring Application Context 中的一个 bean。使用 GET调用/service-registry会返回Registration. 使用带有 JSON 正文的同一端点的 POST 将当前状态更改为Registration新值。JSON 正文必须包含status具有首选值的字段。请参阅ServiceRegistry您在更新状态时使用的实现文档以获取允许的值以及为状态返回的值。例如,Eureka 支持的状态是UPDOWNOUT_OF_SERVICEUNKNOWN

2.3. Spring RestTemplate 作为负载均衡器客户端

您可以将 a 配置RestTemplate为使用负载均衡器客户端。要创建 load-balanced RestTemplate,请创建 aRestTemplate @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 需要使用虚拟主机名(即服务名,而不是主机名)。BlockingLoadBalancerClient 用于创建完整的物理地址。

要使用负载均衡RestTemplate,您需要在类路径中实现负载均衡器。将Spring Cloud LoadBalancer starter添加到您的项目中以使用它。

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

如果要使用@LoadBalanced WebClient.Builder,则需要在类路径中实现负载均衡器。我们建议您将 Spring Cloud LoadBalancer starter添加到您的项目中。然后,ReactiveLoadBalancer在下面使用。

2.4.1。重试失败的请求

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

如果您想在类路径上使用 Spring Retry 或 Reactive Retry 禁用重试逻辑,您可以设置spring.cloud.loadbalancer.retry.enabled=false.

对于非反应式实现,如果您想BackOffPolicy在重试中实现 a,您需要创建一个类型的 beanLoadBalancedRetryFactory并覆盖该createBackOffPolicy()方法。

对于反应式实现,您只需将其设置spring.cloud.loadbalancer.retry.backoff.enabledfalse.

您可以设置:

  • spring.cloud.loadbalancer.retry.maxRetriesOnSameServiceInstance- 指示应在同一个请求上重试多少次ServiceInstance(针对每个选定实例单独计算)
  • spring.cloud.loadbalancer.retry.maxRetriesOnNextServiceInstance- 指示新选择的请求应重试多少次ServiceInstance
  • spring.cloud.loadbalancer.retry.retryableStatusCodes- 总是重试失败请求的状态码。

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

对于响应式实现,您还可以实现自己的LoadBalancerRetryPolicy以更详细地控制负载平衡调用重试。

单个负载均衡器客户端可以单独配置与上述相同的属性,除了前缀是spring.cloud.loadbalancer.clients.<clientId>.*负载clientId均衡器的名称。

对于负载平衡重试,默认情况下,我们将ServiceInstanceListSupplierbean包装为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重试功能添加一个或多个实现,则需要创建一个类型的 beanLoadBalancedRetryListenerFactory并返回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...
                    }
                }};
            }
        };
    }
}

2.5. 多个RestTemplate对象

如果你想要一个RestTemplate不是负载平衡的,创建一个RestTemplatebean 并注入它。要访问 load-balanced RestTemplate,请在创建时使用@LoadBalanced限定符@Bean,如以下示例所示:

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

请注意在前面的示例中使用@Primary普通声明上的注释来消除不合格注入的歧义。 RestTemplate``@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不是负载平衡的,创建一个WebClientbean 并注入它。要访问 load-balanced WebClient,请在创建时使用@LoadBalanced限定符@Bean,如以下示例所示:

@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 WebFluxWebClient作为负载均衡器客户端

Spring WebFlux 可以使用响应式和非响应式WebClient配置,如主题所述:

2.7.1。Spring WebFluxWebClientReactorLoadBalancerExchangeFilterFunction

您可以配置WebClient为使用ReactiveLoadBalancer. 如果您将Spring Cloud LoadBalancer 启动器添加到您的项目,并且如果spring-webflux在类路径上,ReactorLoadBalancerExchangeFilterFunction则会自动配置。以下示例显示了如何配置 aWebClient以使用反应式负载均衡器:

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

2.7.2. WebClient带有非反应式负载均衡器客户端的Spring WebFlux

如果spring-webflux在类路径上,LoadBalancerExchangeFilterFunction 则为自动配置。但是请注意,这在后台使用了非反应式客户端。以下示例显示了如何配置 aWebClient以使用负载均衡器:

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 与反应式负载平衡器一起使用 。

2.8. 忽略网络接口

有时,忽略某些命名的网络接口很有用,这样它们就可以从服务发现注册中排除(例如,在 Docker 容器中运行时)。可以设置正则表达式列表以导致所需的网络接口被忽略。以下配置忽略了docker0接口和所有以 开头的接口veth

示例 2.application.yml

春天:
  云:
    inetutils:
      被忽略的接口:
        - docker0 
        -veth.*

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

示例 3.bootstrap.yml

春天:
  云:
    inetutils:
      首选网络:
        - 192.168 
        - 10.0

您还可以强制仅使用站点本地地址,如以下示例所示:

示例 4.application.yml

春天:
  云:
    inetutils:
      useOnlySiteLocalInterfaces:真

有关构成站点本地地址的更多详细信息,请参阅Inet4Address.html.isSiteLocalAddress() 。

2.9。HTTP 客户端工厂

Spring Cloud Commons 提供了用于创建 Apache HTTP 客户端 ( ApacheHttpClientFactory) 和 OK HTTP 客户端 ( OkHttpClientFactory) 的 bean。仅当OkHttpClientFactoryOK HTTP jar 在类路径上时才会创建 bean。此外,Spring Cloud Commons 提供了用于创建两个客户端使用的连接管理器的 bean:ApacheHttpClientConnectionManagerFactory用于 Apache HTTP 客户端和OkHttpClientConnectionPoolFactoryOK HTTP 客户端。如果您想自定义如何在下游项目中创建 HTTP 客户端,您可以提供自己的这些 bean 实现。另外,如果你提供一个HttpClientBuilderor类型的 bean OkHttpClient.Builder,默认工厂使用这些构建器作为构建器返回到下游项目的基础。您还可以通过设置spring.cloud.httpclientfactories.apache.enabledspring.cloud.httpclientfactories.ok.enabled来禁用这些 bean 的创建false

2.10。启用的功能

Spring Cloud Commons 提供了一个/features执行器端点。此端点返回类路径上可用的功能以及它们是否已启用。返回的信息包括功能类型、名称、版本和供应商。

2.10.1。特征类型

有两种类型的“特征”:抽象的和命名的。

抽象特征是定义了接口或抽象类并创建了实现的特征,例如DiscoveryClientLoadBalancerClientLockService。抽象类或接口用于在上下文中查找该类型的 bean。显示的版本是bean.getClass().getPackage().getImplementationVersion()

命名特征是没有它们实现的特定类的特征。这些功能包括“断路器”、“API 网关”、“Spring Cloud Bus”等。这些功能需要名称和 bean 类型。

2.10.2。声明功能

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

@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中。

2.11。Spring Cloud 兼容性验证

由于部分用户在设置 Spring Cloud 应用时存在问题,我们决定添加兼容性验证机制。如果您当前的设置与 Spring Cloud 要求不兼容,它将中断,并附上一份报告,显示究竟出了什么问题。

目前,我们验证将哪个版本的 Spring Boot 添加到您的类路径中。

报告示例

******************************
应用程序无法启动
******************* ********

描述:

由于以下原因,您的项目设置与我们的要求不兼容:

- Spring Boot [2.1.0.RELEASE] 与此 Spring Cloud 发布火车不兼容


操作:

考虑应用以下操作:

- 将 Spring Boot 版本更改为以下版本之一 [1.2.x, 1.3.x] 。
你可以在这里找到最新的 Spring Boot 版本 [https://spring.io/projects/spring-boot#learn]。
如果您想了解有关 Spring Cloud Release train 兼容性的更多信息,可以访问此页面 [https://spring.io/projects/spring-cloud#overview] 并查看 [Release Trains] 部分。

要禁用此功能,请设置spring.cloud.compatibility-verifier.enabledfalse。如果要覆盖兼容的 Spring Boot 版本,只需 spring.cloud.compatibility-verifier.compatible-boot-versions使用逗号分隔的兼容 Spring Boot 版本列表设置属性。

3. Spring Cloud 负载均衡器

Spring Cloud 提供了自己的客户端负载均衡器抽象和实现。对于负载平衡机制,ReactiveLoadBalancer添加了接口,并为其提供了基于循环随机的实现。为了让实例从反应ServiceInstanceListSupplier 中进行选择,使用了。目前,我们支持基于服务发现的实现,该实现使用类路径中可用的发现客户端ServiceInstanceListSupplier 从服务发现中检索可用实例。

spring.cloud.loadbalancer.enabled可以通过将值设置为来 禁用 Spring Cloud LoadBalancer false

3.1。在负载平衡算法之间切换

默认使用的ReactiveLoadBalancer实现是RoundRobinLoadBalancer. 要为选定的服务或所有服务切换到不同的实现,您可以使用自定义 LoadBalancer 配置机制

例如,可以通过@LoadBalancerClient注释传递以下配置以切换到使用RandomLoadBalancer

public class CustomLoadBalancerConfiguration {

    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}

@LoadBalancerClient您作为或配置参数 传递的类@LoadBalancerClients不应使用注释@Configuration或超出组件扫描范围。

3.2. Spring Cloud LoadBalancer 集成

为了便于使用 Spring Cloud LoadBalancer,我们提供了ReactorLoadBalancerExchangeFilterFunction可以WebClient与. 您可以在以下部分中查看更多信息和使用示例:BlockingLoadBalancerClient``RestTemplate

3.3. Spring Cloud LoadBalancer 缓存

除了通过每次必须选择实例ServiceInstanceListSupplier来检索实例的基本实现之外,我们还提供了两种缓存实现。DiscoveryClient

3.3.1。咖啡因支持的 LoadBalancer 缓存实现

如果您com.github.ben-manes.caffeine:caffeine在类路径中有,将使用基于 Caffeine 的实现。有关如何配置它的信息,请参阅LoadBalancerCacheConfiguration部分。

如果您使用的是咖啡因,您还可以通过在属性中传递您自己的咖啡因规范来覆盖 LoadBalancer 的默认咖啡因缓存设置。spring.cloud.loadbalancer.cache.caffeine.spec

警告:传递您自己的 Caffeine 规范将覆盖任何其他 LoadBalancerCache 设置,包括常规 LoadBalancer 缓存配置字段,例如ttlcapacity

3.3.2. 默认 LoadBalancer 缓存实现

如果类路径中没有 Caffeine ,将使用DefaultLoadBalancerCache自动附带的。有关如何配置它的信息,spring-cloud-starter-loadbalancer请参阅LoadBalancerCacheConfiguration部分。

要使用 Caffeine 而不是默认缓存,请将com.github.ben-manes.caffeine:caffeine依赖项添加到类路径。

3.3.3. 负载均衡器缓存配置

您可以设置自己的ttl值(写入后条目应过期的时间),表示为Duration,通过将String符合Spring Boot的转换语法传递StringDuration转换器语法。作为spring.cloud.loadbalancer.cache.ttl财产的价值。spring.cloud.loadbalancer.cache.capacity您还可以通过设置属性的值来设置自己的 LoadBalancer 缓存初始容量。

默认设置包括ttl设置为 35 秒,默认设置initialCapacity256.

您还可以通过将值设置为spring.cloud.loadbalancer.cache.enabled 来完全禁用 loadBalancer 缓存false

尽管基本的、非缓存的实现对于原型设计和测试很有用,但它的效率远低于缓存版本,因此我们建议始终在生产中使用缓存版本。DiscoveryClient例如,如果缓存已由实现完成,EurekaDiscoveryClient则应禁用负载平衡器缓存以防止双重缓存。

3.4. 基于区域的负载平衡

为了启用基于区域的负载平衡,我们提供了ZonePreferenceServiceInstanceListSupplier. 我们使用DiscoveryClient-specificzone配置(例如,eureka.instance.metadata-map.zone)来选择客户端尝试过滤可用服务实例的区域。

您还可以DiscoveryClient通过设置spring.cloud.loadbalancer.zone属性的值来覆盖特定区域设置。

目前,只有 Eureka Discovery Client 被检测来设置 LoadBalancer 区域。对于其他发现客户端,请设置该spring.cloud.loadbalancer.zone属性。更多仪器即将推出。

为了确定检索到的区域ServiceInstance,我们检查"zone"其元数据映射中键下的值。

ZonePreferenceServiceInstanceListSupplier过滤器检索实例并仅返回同一区域内的实例。如果该区域是null或同一区域内没有实例,则返回所有检索到的实例。

为了使用基于区域的负载平衡方法,您必须在自定义配置ZonePreferenceServiceInstanceListSupplier中实例化一个bean 。

我们使用委托来处理ServiceInstanceListSupplierbean。我们建议在构造函数中传递一个DiscoveryClientServiceInstanceListSupplier委托,ZonePreferenceServiceInstanceListSupplier然后用 a 包装后者CachingServiceInstanceListSupplier以利用LoadBalancer 缓存机制

您可以使用此示例配置进行设置:

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withZonePreference()
                    .withCaching()
                    .build(context);
    }
}

3.5. LoadBalancer 的实例健康检查

可以为 LoadBalancer 启用计划的 HealthCheck。是为此提供的HealthCheckServiceInstanceListSupplier 。它定期验证委托提供的实例 ServiceInstanceListSupplier是否仍然存在,并且只返回健康的实例,除非没有 - 然后它返回所有检索到的实例。

这种机制在使用SimpleDiscoveryClient. 对于由实际 Service Registry 支持的客户端,没有必要使用,因为我们在查询外部 ServiceDiscovery 后已经获得了健康的实例。

还建议将此供应商用于每个服务具有少量实例的设置,以避免在失败的实例上重试调用。

如果使用任何服务发现支持的供应商,通常不需要添加这种健康检查机制,因为我们直接从服务注册中检索实例的健康状态。

HealthCheckServiceInstanceListSupplier依赖于委托通量提供的更新实例。在极少数情况下,当您想要使用不刷新实例的委托时,即使实例列表可能会更改(例如DiscoveryClientServiceInstanceListSupplier我们提供的),您也可以设置spring.cloud.loadbalancer.health-check.refetch-instancestrueHealthCheckServiceInstanceListSupplier. 然后,您还可以通过修改值来调整刷新间隔,并选择通过设置为spring.cloud.loadbalancer.health-check.refetch-instances-interval禁用额外的运行状况检查重复,因为每个实例重新获取也会触发运行状况检查。 spring.cloud.loadbalancer.health-check.repeat-health-check``false

HealthCheckServiceInstanceListSupplier使用以 . 为前缀的属性 spring.cloud.loadbalancer.health-check。您可以为调度程序设置initialDelayinterval 。您可以通过设置spring.cloud.loadbalancer.health-check.path.default属性的值来设置运行状况检查 URL 的默认路径。您还可以通过设置属性的值来为任何给定服务设置特定值spring.cloud.loadbalancer.health-check.path.[SERVICE_ID],并替换[SERVICE_ID]为您的服务的正确 ID。如果[SERVICE_ID]未指定,/actuator/health则默认使用。如果将[SERVICE_ID]值设置为null或为空,则不会执行运行状况检查。您还可以通过设置 的值来为运行状况检查请求设置自定义端口spring.cloud.loadbalancer.health-check.port。如果没有设置,则在服务实例上请求的服务可用的端口。

如果您依赖默认路径 ( /actuator/health),请确保添加spring-boot-starter-actuator到协作者的依赖项,除非您计划自己添加这样的端点。

为了使用健康检查调度程序方法,您必须在自定义配置HealthCheckServiceInstanceListSupplier中实例化一个bean 。

我们使用委托来处理ServiceInstanceListSupplierbean。我们建议在 的构造函数中传递一个DiscoveryClientServiceInstanceListSupplier委托HealthCheckServiceInstanceListSupplier

您可以使用此示例配置进行设置:

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withHealthChecks()
                    .build(context);
        }
    }

对于非反应性堆栈,使用withBlockingHealthChecks(). 您还可以传递您自己的WebClientRestTemplate实例以用于检查。

HealthCheckServiceInstanceListSupplier有自己的基于 Reactor Flux 的缓存机制replay()。因此,如果正在使用它,您可能希望跳过使用CachingServiceInstanceListSupplier.

3.6. LoadBalancer 的相同实例首选项

您可以设置 LoadBalancer,使其更喜欢先前选择的实例(如果该实例可用)。

为此,您需要使用SameInstancePreferenceServiceInstanceListSupplier. 您可以通过设置spring.cloud.loadbalancer.configurationsto的值same-instance-preference或提供您自己的ServiceInstanceListSupplierbean 来配置它——例如:

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withSameInstancePreference()
                    .build(context);
        }
    }

这也是 Zookeeper 的替代品StickyRule

3.7. LoadBalancer 的基于请求的粘性会话

您可以设置 LoadBalancer,使其更喜欢instanceId请求 cookie 中提供的实例。如果请求通过ClientRequestContext或传递给 LoadBalancer ServerHttpRequestContext,我们目前支持这一点,SC LoadBalancer 交换过滤器函数和过滤器使用它们。

为此,您需要使用RequestBasedStickySessionServiceInstanceListSupplier. 您可以通过设置spring.cloud.loadbalancer.configurationsto的值request-based-sticky-session或提供您自己的ServiceInstanceListSupplierbean 来配置它——例如:

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withRequestBasedStickySession()
                    .build(context);
        }
    }

对于该功能,在转发请求之前更新所选服务实例(如果该服务实例不可用,则该服务实例可能与原始请求 cookie 中的服务实例不同)是有用的。为此,请将 的值设置spring.cloud.loadbalancer.sticky-session.add-service-instance-cookietrue

默认情况下,cookie 的名称是sc-lb-instance-id. 您可以通过更改spring.cloud.loadbalancer.instance-id-cookie-name属性的值来修改它。

WebClient 支持的负载平衡当前支持此功能。

3.8. Spring Cloud LoadBalancer 提示

Spring Cloud LoadBalancer 允许您设置String在对象中传递给 LoadBalancer 的提示,Request并且以后可以在ReactiveLoadBalancer可以处理它们的实现中使用这些提示。

您可以通过设置spring.cloud.loadbalancer.hint.default属性的值来为所有服务设置默认提示。您还可以通过设置属性的值来为任何给定服务设置特定值spring.cloud.loadbalancer.hint.[SERVICE_ID],并替换[SERVICE_ID]为您的服务的正确 ID。如果用户未设置提示,default则使用。

3.9. 基于提示的负载平衡

我们还提供了一个HintBasedServiceInstanceListSupplier,它是ServiceInstanceListSupplier基于提示的实例选择的实现。

HintBasedServiceInstanceListSupplier检查提示请求标头(默认标头名称为X-SC-LB-Hint,但您可以通过更改spring.cloud.loadbalancer.hint-header-name属性的值来修改它),如果找到提示请求标头,则使用标头中传递的提示值过滤服务实例。

如果未添加任何提示头,则HintBasedServiceInstanceListSupplier使用属性中的提示值来过滤服务实例。

如果没有通过标头或属性设置提示,则返回委托提供的所有服务实例。

过滤时,HintBasedServiceInstanceListSupplier查找hint在其metadataMap. 如果没有找到匹配的实例,则返回委托提供的所有实例。

您可以使用以下示例配置进行设置:

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withHints()
                    .withCaching()
                    .build(context);
    }
}

3.10。转换负载均衡的 HTTP 请求

您可以使用 selectedServiceInstance来转换负载平衡的 HTTP 请求。

对于RestTemplate,需要实现和定义LoadBalancerRequestTransformer如下:

@Bean
public LoadBalancerRequestTransformer transformer() {
    return new LoadBalancerRequestTransformer() {
        @Override
        public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
            return new HttpRequestWrapper(request) {
                @Override
                public HttpHeaders getHeaders() {
                    HttpHeaders headers = new HttpHeaders();
                    headers.putAll(super.getHeaders());
                    headers.add("X-InstanceId", instance.getInstanceId());
                    return headers;
                }
            };
        }
    };
}

对于WebClient,需要实现和定义LoadBalancerClientRequestTransformer如下:

@Bean
public LoadBalancerClientRequestTransformer transformer() {
    return new LoadBalancerClientRequestTransformer() {
        @Override
        public ClientRequest transformRequest(ClientRequest request, ServiceInstance instance) {
            return ClientRequest.from(request)
                    .header("X-InstanceId", instance.getInstanceId())
                    .build();
        }
    };
}

如果定义了多个转换器,它们将按照定义 Bean 的顺序应用。或者,您可以使用LoadBalancerRequestTransformer.DEFAULT_ORDERLoadBalancerClientRequestTransformer.DEFAULT_ORDER来指定顺序。

3.11。Spring Cloud LoadBalancer 启动器

我们还提供了一个启动器,允许您在 Spring Boot 应用程序中轻松添加 Spring Cloud LoadBalancer。要使用它,只需org.springframework.cloud:spring-cloud-starter-loadbalancer在构建文件中添加 Spring Cloud 依赖项即可。

Spring Cloud LoadBalancer starter 包括 Spring Boot CachingEvictor

3.12。传递您自己的 Spring Cloud LoadBalancer 配置

你也可以使用@LoadBalancerClient注解来传递你自己的负载均衡器客户端配置,传递负载均衡器客户端的名称和配置类,如下:

@Configuration
@LoadBalancerClient(value = "stores", configuration = CustomLoadBalancerConfiguration.class)
public class MyConfiguration {

    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
}
  • 小费

    为了使您自己的 LoadBalancer 配置工作更容易,我们builder()在类中添加了一个方法ServiceInstanceListSupplier

  • 小费

    spring.cloud.loadbalancer.configurations您还可以通过将属性的值设置为与缓存一起zone-preference使用ZonePreferenceServiceInstanceListSupplier或与缓存health-check一起使用来使用我们的替代预定义配置来代替默认配置HealthCheckServiceInstanceListSupplier

ServiceInstanceListSupplier您可以使用此功能来实例化或的不同实现,ReactorLoadBalancer由您编写或由我们作为替代方案提供(例如ZonePreferenceServiceInstanceListSupplier)以覆盖默认设置。

您可以在此处查看自定义配置的示例。

注释value参数(stores在上面的示例中)指定了我们应该使用给定的自定义配置将请求发送到的服务的服务 ID。

您还可以通过注解传递多个配置(用于多个负载均衡器客户端)@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();
    }
}

@LoadBalancerClient您作为或配置参数 传递的类@LoadBalancerClients不应使用注释@Configuration或超出组件扫描范围。

3.13。Spring Cloud LoadBalancer 生命周期

使用自定义 LoadBalancer 配置注册可能有用的一种 bean 类型是LoadBalancerLifecycle.

这些LoadBalancerLifecyclebean 提供了回调方法,命名为onStart(Request<RC> request)onStartRequest(Request<RC> request, Response<T> lbResponse)onComplete(CompletionContext<RES, T, RC> completionContext)您应该实现这些方法以指定在负载平衡之前和之后应该执行哪些操作。

onStart(Request<RC> request)接受一个Request对象作为参数。它包含用于选择适当实例的数据,包括下游客户端请求和提示onStartRequest还将Request对象和Response<T>对象作为参数。另一方面,CompletionContext对象被提供给该onComplete(CompletionContext<RES, T, RC> completionContext)方法。它包含 LoadBalancer Response,包括选定的服务实例、Status针对该服务实例执行的请求的 和(如果可用)返回给下游客户端的响应,以及(如果发生异常)对应的Throwable.

supports(Class requestContextClass, Class responseClass, Class serverTypeClass)方法可用于确定所讨论的处理器是否处理所提供类型的对象。如果没有被用户覆盖,则返回true.

上述方法调用中,RC表示RequestContext类型,RES表示客户端响应类型,T表示返回服务器类型。

如果您使用自定义 HTTP 状态代码,您将遇到异常。为了防止这种情况,您可以设置 的值spring.cloud.loadbalancer.use-raw-status-code-in-response-data。它将导致使用原始状态代码而不是HttpStatus枚举。然后将使用 in 中的httpStatus字段ResponseData,但您将能够从该rawHttpStatus字段中获取原始状态代码。

3.14。Spring Cloud LoadBalancer 统计

我们提供了一个LoadBalancerLifecycle名为 的 bean MicrometerStatsLoadBalancerLifecycle,它使用 Micrometer 提供负载平衡调用的统计信息。

为了将此 bean 添加到您的应用程序上下文中,请设置 to 的值并使其spring.cloud.loadbalancer.stats.micrometer.enabled可用(例如,通过将Spring Boot Actuator添加到您的项目中)。true``MeterRegistry

MicrometerStatsLoadBalancerLifecycle在 中注册以下仪表MeterRegistry

  • loadbalancer.requests.active:一个仪表,允许您监视任何服务实例的当前活动请求的数量(可通过标签获得的服务实例数据);
  • loadbalancer.requests.success: 一个计时器,用于测量任何负载平衡请求的执行时间,这些请求已在将响应传递给底层客户端时结束;
  • loadbalancer.requests.failed:一个计时器,用于测量任何以异常结束的负载平衡请求的执行时间;
  • loadbalancer.requests.discard:一个计数器,用于测量丢弃的负载平衡请求的数量,即 LoadBalancer 尚未检索到运行请求的服务实例的请求。

在可用时,通过标签将有关服务实例、请求数据和响应数据的附加信息添加到指标中。

对于某些实现,例如BlockingLoadBalancerClient,请求和响应数据可能不可用,因为我们从参数建立泛型类型并且可能无法确定类型并读取数据。

当为给定仪表添加至少一条记录时,仪表将在注册表中注册。

您可以通过添加来进一步配置这些指标的行为(例如,添加发布百分比和直方图)。 MeterFilters

3.15。配置单个 LoadBalancerClients

单个负载均衡器客户端可以单独配置不同的前缀**,其中****负载均衡器的名称。**可以在命名空间中设置默认配置值,并将优先与客户端特定值合并spring.cloud.loadbalancer.clients.<clientId>.clientId``spring.cloud.loadbalancer.

示例 5.application.yml

春天:
  云:
    负载平衡器:健康
      检查:
        初始延迟:1s
      客户端:
        myclient:
          健康检查:
            间隔:30s

上面的示例将产生一个合并的健康检查@ConfigurationProperties对象initial-delay=1sinterval=30s

除以下全局属性外,每个客户端的配置属性适用于大多数属性:

  • spring.cloud.loadbalancer.enabled- 全局启用或禁用负载平衡
  • spring.cloud.loadbalancer.retry.enabled- 全局启用或禁用负载平衡重试。如果全局启用它,您仍然可以使用client-prefixed 属性禁用特定客户端的重试,但反之则不行
  • spring.cloud.loadbalancer.cache.enabled- 全局启用或禁用 LoadBalancer 缓存。如果您全局启用它,您仍然可以通过创建不包含在委托层次结构中的自定义配置来禁用特定客户端的缓存,但反之则不行。CachingServiceInstanceListSupplier``ServiceInstanceListSupplier
  • spring.cloud.loadbalancer.stats.micrometer.enabled- 全局启用或禁用 LoadBalancer Micrometer 指标

对于已经使用映射的属性,您可以在不使用clients关键字的情况下为每个客户端指定不同的值(例如 , hintshealth-check.path,我们保留了该行为以保持库向后兼容。它将在下一个主要版本中进行修改。

4. Spring Cloud 断路器

4.1。介绍

Spring Cloud 断路器提供了跨不同断路器实现的抽象。它提供了在您的应用程序中使用的一致 API,让您(开发人员)选择最适合您的应用程序需求的断路器实现。

4.1.1。支持的实现

Spring Cloud 支持以下断路器实现:

4.2. 核心概念

要在代码中创建断路器,您可以使用CircuitBreakerFactoryAPI。当您在类路径中包含 Spring Cloud Circuit Breaker 启动器时,会自动为您创建实现此 API 的 bean。以下示例显示了如何使用此 API 的简单示例:

@Service
public static class DemoControllerService {
    private RestTemplate rest;
    private CircuitBreakerFactory cbFactory;

    public DemoControllerService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
        this.rest = rest;
        this.cbFactory = cbFactory;
    }

    public String slow() {
        return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback");
    }

}

CircuitBreakerFactory.createAPI 创建一个名为 的类的实例CircuitBreaker。该run方法需要 aSupplier和 a Function。这Supplier是您要包装在断路器中的代码。这Function是在断路器跳闸时运行的回退。传递了Throwable导致触发回退的函数。如果您不想提供回退,您可以选择排除回退。

4.2.1。无功代码中的断路器

如果 Project Reactor 在类路径上,您也可以将ReactiveCircuitBreakerFactory其用于您的反应代码。以下示例显示了如何执行此操作:

@Service
public static class DemoControllerService {
    private ReactiveCircuitBreakerFactory cbFactory;
    private WebClient webClient;


    public DemoControllerService(WebClient webClient, ReactiveCircuitBreakerFactory cbFactory) {
        this.webClient = webClient;
        this.cbFactory = cbFactory;
    }

    public Mono<String> slow() {
        return webClient.get().uri("/slow").retrieve().bodyToMono(String.class).transform(
        it -> cbFactory.create("slow").run(it, throwable -> return Mono.just("fallback")));
    }
}

ReactiveCircuitBreakerFactory.createAPI 创建一个名为 的类的实例ReactiveCircuitBreaker。该run方法采用 aMono或 aFlux并将其包装在断路器中。您可以选择配置一个 fallback Function,如果断路器跳闸并通过Throwable 导致故障的原因,它将被调用。

4.3. 配置

您可以通过创建 bean 类型来配置您的断路器Customizer。该Customizer接口有一个方法(称为customize),Object用于自定义。

有关如何自定义给定实现的详细信息,请参阅以下文档:

一些CircuitBreaker实现,例如每次Resilience4JCircuitBreaker调用方法的调用。它可能效率低下。在这种情况下,您可以使用方法。在多次调用没有意义的情况下很有用,例如,在使用 Resilience4j 的 events 的情况下。customize``CircuitBreaker#run``CircuitBreaker#once``customize

以下示例显示了每个io.github.resilience4j.circuitbreaker.CircuitBreaker使用事件的方式。

Customizer.once(circuitBreaker -> {
  circuitBreaker.getEventPublisher()
    .onStateTransition(event -> log.info("{}: {}", event.getCircuitBreakerName(), event.getStateTransition()));
}, CircuitBreaker::getName)

5. CachedRandomPropertySource

Spring Cloud Context 提供了一个PropertySource基于键缓存随机值的方法。在缓存功能之外,它与 Spring Boot 的RandomValuePropertySource. 如果您想要一个即使在 Spring 应用程序上下文重新启动后仍保持一致的随机值,此随机值可能很有用。属性值采用缓存中的键在cachedrandom.[yourkey].[type]哪里的形式。yourkeytype值可以是 Spring Boot 支持的任何类型RandomValuePropertySource

myrandom=${cachedrandom.appname.value}

6. 安全

6.1。单点登录

所有 OAuth2 SSO 和资源服务器功能都在 1.3 版中移至 Spring Boot。您可以在Spring Boot 用户指南中找到文档 。

6.1.1. 客户端令牌中继

如果您的应用程序是面向 OAuth2 客户端的用户(即已声明 @EnableOAuth2Sso@EnableOAuth2Client),那么它具有 OAuth2ClientContext来自 Spring Boot 的请求范围内。OAuth2RestTemplate您可以从此上下文和 autowired创建自己的OAuth2ProtectedResourceDetails,然后上下文将始终将访问令牌转发到下游,如果访问令牌过期,也会自动刷新它。(这些是 Spring Security 和 Spring Boot 的特性。)

6.1.2. 资源服务器令牌中继

如果您的应用程序有@EnableResourceServer,您可能希望将传入的令牌向下游中继到其他服务。如果您使用 a RestTemplate联系下游服务,那么这只是如何创建具有正确上下文的模板的问题。

如果您的服务用于UserInfoTokenServices验证传入令牌(即,它正在使用security.oauth2.user-info-uri 配置),那么您可以简单地OAuth2RestTemplate 使用自动装配创建一个OAuth2ClientContext(它将在验证过程到达后端代码之前填充)。等效地(使用 Spring Boot 1.4),您可以在配置中注入 UserInfoRestTemplateFactory并获取它OAuth2RestTemplate。例如:

MyConfiguration.java

@Bean
public OAuth2RestTemplate restTemplate(UserInfoRestTemplateFactory factory) {
    return factory.getUserInfoRestTemplate();
}

然后,此其余模板将具有OAuth2ClientContext 身份验证过滤器使用的相同(请求范围),因此您可以使用它来发送具有相同访问令牌的请求。

如果您的应用程序未使用UserInfoTokenServices但仍是客户端(即它声明@EnableOAuth2Client@EnableOAuth2Sso),则使用 Spring Security CloudOAuth2RestOperations用户从 an 创建的任何@Autowired OAuth2Context内容也将转发令牌。此功能默认实现为 MVC 处理程序拦截器,因此它仅适用于 Spring MVC。如果您不使用 MVC,则可以使用自定义过滤器或包装 an 的 AOP 拦截器 AccessTokenContextRelay来提供相同的功能。

这是一个基本示例,显示了使用在其他地方创建的自动装配的休息模板(“foo.com”是一个资源服务器,接受与周围应用程序相同的令牌):

MyController.java

@Autowired
private OAuth2RestOperations restTemplate;

@RequestMapping("/relay")
public String relay() {
    ResponseEntity<String> response =
      restTemplate.getForEntity("https://foo.com/bar", String.class);
    return "Success! (" + response.getBody() + ")";
}

如果您不想转发令牌(这是一个有效的选择,因为您可能想充当自己,而不是向您发送令牌的客户端),那么您只需要创建自己的 OAuth2Context而不是自动装配默认值一。

Feign 客户端也会选择一个拦截器, OAuth2ClientContext如果它可用的话,他们也应该在任何地方做一个令牌中继RestTemplate

7.配置属性

要查看所有 Spring Cloud Commons 相关配置属性的列表,请查看附录页面

0

评论区