|
此版本仍在开发中,尚未稳定。如需最新的稳定版本,请使用 Spring Framework 7.0.6! |
韧性特性
自7.0版本起,Spring框架核心包含了通用的韧性特性,特别是用于方法调用的
@Retryable 和
@ConcurrencyLimit 注解,以及
编程式重试支持。
@Retryable
@Retryable 是一个注解,用于指定单个方法(在方法级别声明注解)或给定类层次结构中所有通过代理调用的方法(在类型级别声明注解)的重试特性。
@Retryable
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
默认情况下,方法调用将在抛出任何异常时重试:在初次失败后最多尝试3次重试(maxRetries = 3),每次重试之间的延迟为1秒。
|
一个 例如,如果将 |
如有需要,这可以针对每个方法具体调整——例如,通过限制includes和excludes属性来重试的异常。提供的异常类型将与失败调用抛出的异常以及嵌套原因进行匹配。
@Retryable(MessageDeliveryException.class)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
@Retryable(MessageDeliveryException.class) 是
@Retryable(includes = MessageDeliveryException.class) 的快捷方式。 |
|
对于高级使用场景,您可以通过在 自定义谓词可以与 |
或者,尝试4次重试,采用指数退避策略并带有一定的抖动:
@Retryable(
includes = MessageDeliveryException.class,
maxRetries = 4,
delay = 100,
jitter = 10,
multiplier = 2,
maxDelay = 1000)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
最后但同样重要的是,@Retryable 也适用于具有响应式返回类型的响应式方法,以装饰带有 Reactor 重试能力的管道:
@Retryable(maxRetries = 4, delay = 100)
public Mono<Void> sendNotification() {
return Mono.from(...); (1)
}
| 1 | 这个原始的Mono将通过重试规范进行装饰。 |
详细了解各种特性,请参阅@Retryable中提供的注解属性。
@Retryable 中的多个属性具有 String 变体,提供属性占位符和 SpEL 支持,作为上述示例中使用特定类型注解属性的替代方案。 |
@ConcurrencyLimit
@ConcurrencyLimit 是一个注解,用于指定单个方法(在方法级别声明该注解)或给定类层次结构中所有通过代理调用的方法(在类型级别声明该注解)的并发限制。
@ConcurrencyLimit(10)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
这旨在保护目标资源,防止其被过多线程同时访问,类似于线程池或连接池的大小限制效果,当达到限制时会阻止访问。
您可以选择性地将限制设置为 1,从而有效锁定对目标Bean实例的访问:
@ConcurrencyLimit(1)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
这种限制在使用虚拟线程时特别有用,因为虚拟线程通常没有线程池限制。对于异步任务,可以在
SimpleAsyncTaskExecutor
上施加此约束。对于同步调用,此注解通过
ConcurrencyThrottleInterceptor
提供了等效的行为,该行为自Spring Framework 1.0起就已可用于AOP框架的编程式使用。
@ConcurrencyLimit 还具有一个 limitString 属性,可提供属性占位符和SpEL支持,作为上述基于 int 的示例的替代方案。 |
启用弹性方法
就像Spring许多基于注解的核心特性一样,@Retryable和@ConcurrencyLimit被设计为元数据,您可以选择遵守或忽略。启用韧性注解处理最便捷的方式是在相应的@Configuration类上声明
@EnableResilientMethods。
另外,通过在上下文中定义一个RetryAnnotationBeanPostProcessor或ConcurrencyLimitBeanPostProcessor的bean,这些注解可以被单独启用。
程序化重试支持
与在ApplicationContext中注册的bean的方法指定重试语义的声明式方法@Retryable相比,RetryTemplate提供了一个用于重试任意代码块的编程式API。
具体来说,一个RetryTemplate会执行并可能根据配置的Retryable策略重试
RetryPolicy操作。
var retryTemplate = new RetryTemplate(); (1)
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));
| 1 | 隐式使用RetryPolicy.withDefaults()。 |
默认情况下,可重试操作会针对抛出的任何异常进行重试:在初次失败后最多尝试3次重试(maxRetries = 3次),每次尝试之间延迟1秒。
|
可重试操作至少执行一次,并最多重试 例如,如果将 |
如果只需要自定义重试次数,您可以使用如下的
RetryPolicy.withMaxRetries() 工厂方法来实现。
var retryTemplate = new RetryTemplate(RetryPolicy.withMaxRetries(4)); (1)
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));
| 1 | 明确使用了RetryPolicy.withMaxRetries(4)。 |
如需限制重试的异常类型,可通过
includes() 和 excludes() 构建方法来实现。所提供的异常类型将与失败操作抛出的异常及其嵌套原因进行匹配。
var retryPolicy = RetryPolicy.builder()
.includes(MessageDeliveryException.class) (1)
.excludes(...) (2)
.build();
var retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));
| 1 | 指定一个或多个要包含的异常类型。 |
| 2 | 指定一个或多个要排除的异常类型。 |
|
对于高级使用场景,您可以通过在 自定义谓词可以与 |
以下示例展示了如何配置一个RetryPolicy,使其具有4次重试尝试以及一个带有少许抖动的指数退避策略。
var retryPolicy = RetryPolicy.builder()
.includes(MessageDeliveryException.class)
.maxRetries(4)
.delay(Duration.ofMillis(100))
.jitter(Duration.ofMillis(10))
.multiplier(2)
.maxDelay(Duration.ofSeconds(1))
.build();
var retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));
|
一个 |
尽管为RetryPolicy提供的工厂方法和生成器API已涵盖大多数常见的配置场景,但您可以通过实现自定义的RetryPolicy来完全控制应触发重试的异常类型以及使用的BackOff策略。请注意,您还可以通过RetryPolicy.Builder中的backOff()方法配置自定义的BackOff策略。