@Retryable
注解简介
@Retryable
注解是 Spring Retry 模块提供的,用于自动重试可能会失败的方法。在微服务架构和分布式系统中,服务之间的调用可能会因为网络问题、服务繁忙等原因失败。使用 @Retryable
可以提高应用的稳定性和容错能力 1。
使用步骤
(1)添加依赖
首先,确保你的 Spring Boot 项目中包含了 spring-retry
依赖。如果使用 Maven,可以在 pom.xml
文件中添加以下依赖:
XML
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
(2)启用重试
在 Spring Boot 应用的主类或配置类上添加 @EnableRetry
注解,启用重试功能 16。
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
@SpringBootApplication
@EnableRetry
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
(3)使用 @Retryable
注解
在需要进行重试的方法上添加 @Retryable
注解。
java
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Retryable(value = {MyNetworkException.class}, maxAttempts = 3)
public String fetchDataFromRemote() {
System.out.println("尝试调用远程服务...");
// 模拟可能失败的远程调用
if (Math.random() < 0.5) {
throw new MyNetworkException("网络异常");
}
return "调用成功";
}
}
在这个例子中,fetchDataFromRemote
方法在抛出 MyNetworkException
异常时会进行重试,最多重试 3 次。
@Retryable
注解的属性
@Retryable
注解提供了多个属性,用于配置重试策略 1。
-
value
/exception
指定需要重试的异常类型。可以指定一个或多个异常类。
java@Retryable(value = {MyNetworkException.class, TimeoutException.class}) public String fetchDataFromRemote() { // ... }
-
maxAttempts
指定最大重试次数,包括第一次调用。默认值为 3。
java@Retryable(value = MyNetworkException.class, maxAttempts = 5) public String fetchDataFromRemote() { // ... }
-
backoff
指定重试之间的退避策略。可以使用
@Backoff
注解配置退避策略。delay
:重试之间的延迟时间,单位为毫秒。multiplier
:延迟倍数,用于实现指数退避。random
:是否在延迟时间上增加一个随机值,以避免多个服务同时重试。
javaimport org.springframework.retry.annotation.Backoff; @Retryable(value = MyNetworkException.class, backoff = @Backoff(delay = 2000, multiplier = 1.5)) public String fetchDataFromRemote() { // ... }
在这个例子中,第一次重试延迟 2 秒,第二次重试延迟 3 秒 (2 * 1.5),以此类推。
@Recover
注解
@Recover
注解用于指定重试失败后的恢复方法。恢复方法的参数必须与重试方法抛出的异常类型相匹配,并且必须在同一个类中。
java
import org.springframework.retry.annotation.Recover;
@Service
public class MyService {
@Retryable(value = {MyNetworkException.class}, maxAttempts = 3)
public String fetchDataFromRemote() {
System.out.println("尝试调用远程服务...");
// 模拟可能失败的远程调用
if (Math.random() < 0.5) {
throw new MyNetworkException("网络异常");
}
return "调用成功";
}
@Recover
public String recover(MyNetworkException e) {
System.out.println("重试失败,执行恢复逻辑...");
// 处理异常的逻辑,例如返回默认值或记录日志
return "默认值";
}
}
在这个例子中,如果 fetchDataFromRemote
方法重试 3 次后仍然失败,会调用 recover
方法处理 MyNetworkException
异常。
-
第一个参数必须是
Throwable
类型或其子类型:@Recover
方法的第一个参数必须是Throwable
类型,或者@Retryable
方法中声明的异常类型(或其父类)。- 这个参数用于接收
@Retryable
方法抛出的异常。
-
后续参数必须与
@Retryable
方法的参数类型和顺序一致:@Recover
方法的后续参数必须与对应的@Retryable
方法的参数类型和顺序完全一致。- 这些参数用于将
@Retryable
方法的参数传递给@Recover
方法。
-
参数数量:
@Recover
方法的参数数量必须等于@Retryable
方法的参数数量加 1(用于接收异常)。
当被
@Retryable
注解的方法经过多次重试都失败,并且成功调用了@Recover
注解的恢复方法后,最初调用@Retryable
方法的方法会拿到@Recover
方法的返回值。
- 初始调用: 外部方法调用被
@Retryable
注解的方法。- 重试失败:
@Retryable
方法执行失败,并且经过配置的重试次数后仍然失败。- 调用
@Recover
: Spring Retry 框架会自动查找并调用与@Retryable
方法签名匹配的@Recover
方法。- 返回结果:
@Recover
方法执行完毕后,会将它的返回值返回给最初调用@Retryable
方法的外部方法。关键点:
@Recover
方法的返回值类型必须与@Retryable
方法的返回值类型相同,这样才能保证类型安全。- 如果
@Recover
方法本身也抛出了异常,那么这个异常会直接抛给最初的调用者,不会再进行重试。如果你没有定义
@Recover
注解的方法,并且@Retryable
注解的方法在经过所有重试次数后仍然失败,那么最初调用@Retryable
方法的地方会抛出RetryException
异常。具体流程如下:
- 初始调用: 外部方法调用被
@Retryable
注解的方法。- 重试失败:
@Retryable
方法执行失败,并且经过配置的重试次数后仍然失败。- 没有
@Recover
方法: Spring Retry 框架找不到与@Retryable
方法签名匹配的@Recover
方法。- 抛出
RetryException
: Spring Retry 框架会抛出一个RetryException
异常,该异常会传递给最初调用@Retryable
方法的外部方法。