文章摘要(AI生成)
云原生是一种应用程序开发风格,它鼓励在持续交付和价值驱动开发领域轻松采用最佳实践。一个相关的学科是构建12 要素应用程序,其中开发实践与交付和运营目标保持一致——例如,通过使用声明式编程以及管理和监控。Spring Cloud 以多种特定方式促进了这些开发风格。起点是分布式系统中的所有组件都需要轻松
云原生是一种应用程序开发风格,它鼓励在持续交付和价值驱动开发领域轻松采用最佳实践。一个相关的学科是构建12 要素应用程序,其中开发实践与交付和运营目标保持一致——例如,通过使用声明式编程以及管理和监控。Spring Cloud 以多种特定方式促进了这些开发风格。起点是分布式系统中的所有组件都需要轻松访问的一组特性。
Spring Boot涵盖了其中许多功能,Spring Cloud 在此基础上构建。Spring Cloud 以两个库的形式提供了更多功能:Spring Cloud Context 和 Spring Cloud Commons。ApplicationContext
Spring 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.yml
或application.yml
)。要将该属性spring.application.name
用作应用程序的上下文 ID,您必须将其设置为bootstrap.[properties | yml]
.
如果要检索特定的配置文件配置,还应该spring.profiles.active
在bootstrap.[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。@Beans
type有一个特殊的合同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"));
}
}
传入的Environment
是ApplicationContext
即将被创建的那个——换句话说,我们为其提供额外的属性源的那个。它已经有其正常的 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 功能)来验证更改是否绑定到@ConfigurationProperties
bean 。/configprops
例如,aDataSource
可以maxPoolSize
在运行时更改(Spring Boot 默认DataSource
创建的是@ConfigurationProperties
bean)并动态增加容量。重新绑定@ConfigurationProperties
不涵盖另一大类用例,在这些用例中,您需要对刷新进行更多控制,并且需要对整个ApplicationContext
. 为了解决这些问题,我们有@RefreshScope
.
1.9。刷新范围
当配置发生变化时,@Bean
标记为的 Spring@RefreshScope
会得到特殊处理。此功能解决了仅在初始化时才注入其配置的有状态 bean 的问题。例如,如果在DataSource
通过 更改数据库 URL 时 a 有打开的连接Environment
,您可能希望这些连接的持有者能够完成他们正在做的事情。然后,下一次从池中借用连接时,它会使用新的 URL 获得一个。
有时,甚至可能强制@RefreshScope
在某些只能初始化一次的 bean 上应用注释。如果一个 bean 是“不可变的”,你必须在 bean 上注解@RefreshScope
或者在属性键下指定类名:spring.cloud.refresh.extra-refreshable
.
如果你有一个DataSource
bean HikariDataSource
,它不能被刷新。它是 的默认值spring.cloud.refresh.never-refreshable
。DataSource
如果需要刷新,请 选择不同的实现。
刷新作用域 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
重新加载引导上下文并刷新@RefreshScope
bean。/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
注解。这会查找DiscoveryClient
和ReactiveDiscoveryClient
接口的实现META-INF/spring.factories
。发现客户端的实现在键spring.factories
下添加了一个配置类org.springframework.cloud.client.discovery.EnableDiscoveryClient
。实现的示例DiscoveryClient
包括Spring Cloud Netflix Eureka、Spring Cloud Consul Discovery和Spring 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
此复合健康指标基于所有已注册的DiscoveryHealthIndicator
bean。要禁用,请设置spring.cloud.discovery.client.composite-indicator.enabled=false
.
2.1.2. 订购DiscoveryClient
实例
DiscoveryClient
接口扩展Ordered
。这在使用多个发现客户端时很有用,因为它允许您定义返回的发现客户端的顺序,类似于如何对 Spring 应用程序加载的 bean 进行排序。默认情况下,any 的顺序DiscoveryClient
设置为 0
。如果您想为您的自定义DiscoveryClient
实现设置不同的顺序,您只需要重写该getOrder()
方法,以便它返回适合您设置的值。除此之外,您还可以使用属性来设置DiscoveryClient
Spring Cloud 等提供的实现的顺序ConsulDiscoveryClient
,EurekaDiscoveryClient
以及 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
实现。
ZookeeperRegistration
与ZookeeperServiceRegistry
EurekaRegistration
与EurekaServiceRegistry
ConsulRegistration
与ConsulServiceRegistry
如果您正在使用该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
执行器端点。这个端点依赖于Registration
Spring Application Context 中的一个 bean。使用 GET调用/service-registry
会返回Registration
. 使用带有 JSON 正文的同一端点的 POST 将当前状态更改为Registration
新值。JSON 正文必须包含status
具有首选值的字段。请参阅ServiceRegistry
您在更新状态时使用的实现文档以获取允许的值以及为状态返回的值。例如,Eureka 支持的状态是UP
、DOWN
、OUT_OF_SERVICE
和UNKNOWN
。
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.enabled
为false
.
您可以设置:
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
均衡器的名称。
对于负载平衡重试,默认情况下,我们将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
重试功能添加一个或多个实现,则需要创建一个类型的 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
不是负载平衡的,创建一个RestTemplate
bean 并注入它。要访问 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
不是负载平衡的,创建一个WebClient
bean 并注入它。要访问 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 WebFluxWebClient
与ReactorLoadBalancerExchangeFilterFunction
您可以配置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。仅当OkHttpClientFactory
OK HTTP jar 在类路径上时才会创建 bean。此外,Spring Cloud Commons 提供了用于创建两个客户端使用的连接管理器的 bean:ApacheHttpClientConnectionManagerFactory
用于 Apache HTTP 客户端和OkHttpClientConnectionPoolFactory
OK HTTP 客户端。如果您想自定义如何在下游项目中创建 HTTP 客户端,您可以提供自己的这些 bean 实现。另外,如果你提供一个HttpClientBuilder
or类型的 bean OkHttpClient.Builder
,默认工厂使用这些构建器作为构建器返回到下游项目的基础。您还可以通过设置spring.cloud.httpclientfactories.apache.enabled
或spring.cloud.httpclientfactories.ok.enabled
来禁用这些 bean 的创建false
。
2.10。启用的功能
Spring Cloud Commons 提供了一个/features
执行器端点。此端点返回类路径上可用的功能以及它们是否已启用。返回的信息包括功能类型、名称、版本和供应商。
2.10.1。特征类型
有两种类型的“特征”:抽象的和命名的。
抽象特征是定义了接口或抽象类并创建了实现的特征,例如DiscoveryClient
、LoadBalancerClient
或LockService
。抽象类或接口用于在上下文中查找该类型的 bean。显示的版本是bean.getClass().getPackage().getImplementationVersion()
。
命名特征是没有它们实现的特定类的特征。这些功能包括“断路器”、“API 网关”、“Spring Cloud Bus”等。这些功能需要名称和 bean 类型。
2.10.2。声明功能
任何模块都可以声明任意数量的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(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.enabled
为false
。如果要覆盖兼容的 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
- Spring RestTemplate 作为负载均衡器客户端
- Spring WebClient 作为负载均衡器客户端
- Spring WebFlux WebClient 与
ReactorLoadBalancerExchangeFilterFunction
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 缓存配置字段,例如ttl
和capacity
。
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的转换语法传递String
给Duration
转换器语法。作为spring.cloud.loadbalancer.cache.ttl
财产的价值。spring.cloud.loadbalancer.cache.capacity
您还可以通过设置属性的值来设置自己的 LoadBalancer 缓存初始容量。
默认设置包括ttl
设置为 35 秒,默认设置initialCapacity
为256
.
您还可以通过将值设置为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 。
我们使用委托来处理ServiceInstanceListSupplier
bean。我们建议在构造函数中传递一个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-instances
为true
让HealthCheckServiceInstanceListSupplier
. 然后,您还可以通过修改值来调整刷新间隔,并选择通过设置为spring.cloud.loadbalancer.health-check.refetch-instances-interval
禁用额外的运行状况检查重复,因为每个实例重新获取也会触发运行状况检查。 spring.cloud.loadbalancer.health-check.repeat-health-check``false
HealthCheckServiceInstanceListSupplier
使用以 . 为前缀的属性 spring.cloud.loadbalancer.health-check
。您可以为调度程序设置initialDelay
和interval
。您可以通过设置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 。
我们使用委托来处理ServiceInstanceListSupplier
bean。我们建议在 的构造函数中传递一个DiscoveryClientServiceInstanceListSupplier
委托HealthCheckServiceInstanceListSupplier
。
您可以使用此示例配置进行设置:
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withHealthChecks()
.build(context);
}
}
对于非反应性堆栈,使用withBlockingHealthChecks()
. 您还可以传递您自己的WebClient
或RestTemplate
实例以用于检查。
HealthCheckServiceInstanceListSupplier
有自己的基于 Reactor Flux 的缓存机制replay()
。因此,如果正在使用它,您可能希望跳过使用CachingServiceInstanceListSupplier
.
3.6. LoadBalancer 的相同实例首选项
您可以设置 LoadBalancer,使其更喜欢先前选择的实例(如果该实例可用)。
为此,您需要使用SameInstancePreferenceServiceInstanceListSupplier
. 您可以通过设置spring.cloud.loadbalancer.configurations
to的值same-instance-preference
或提供您自己的ServiceInstanceListSupplier
bean 来配置它——例如:
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.configurations
to的值request-based-sticky-session
或提供您自己的ServiceInstanceListSupplier
bean 来配置它——例如:
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-cookie
为true
。
默认情况下,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_ORDER
或LoadBalancerClientRequestTransformer.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 Caching 和Evictor。
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
.
这些LoadBalancerLifecycle
bean 提供了回调方法,命名为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=1s
和interval=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
关键字的情况下为每个客户端指定不同的值(例如 , hints
)health-check.path
,我们保留了该行为以保持库向后兼容。它将在下一个主要版本中进行修改。
4. Spring Cloud 断路器
4.1。介绍
Spring Cloud 断路器提供了跨不同断路器实现的抽象。它提供了在您的应用程序中使用的一致 API,让您(开发人员)选择最适合您的应用程序需求的断路器实现。
4.1.1。支持的实现
Spring Cloud 支持以下断路器实现:
4.2. 核心概念
要在代码中创建断路器,您可以使用CircuitBreakerFactory
API。当您在类路径中包含 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.create
API 创建一个名为 的类的实例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.create
API 创建一个名为 的类的实例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]
哪里的形式。yourkey
该type
值可以是 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 相关配置属性的列表,请查看附录页面。
评论区