这个链接是实例:https://blog.csdn.net/weixin_41381863/article/details/89856440
对注解讲解的比较全;
在项目开发中,经常会遇到需要重试的地方。除了自己写循环(不是那么优雅,也不方便维护,关键是可能还不那么可靠)重试之外,还可以使用spring retry。
spring retry主要实现了重试和熔断。
不适合重试的场景:
参数校验不合法、写操作等(要考虑写是否幂等)都不适合重试。
适合重试的场景:
远程调用超时、网络突然中断等可以重试。
在spring retry中可以指定需要重试的异常类型,并设置每次重试的间隔以及如果重试失败是继续重试还是熔断(停止重试)。
1 快速开始
1、在项目中引入jar包:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<!--还需要aspectjweaver依赖-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
2、将目标类配置为spring的bean,并在配置中加入启动重试功能注解:@EnableRetry(如果是springboot项目,在启动类上添加该注解也可)
@Configuration
@EnableRetry
public class Config
或者
@SpringBootApplication
@EnableRetry
public class Application
3、在需要重试的相关类的方法中加上@Retryable即可实现重试。
@Retryable(Exception.class)
@Override
public String targetMethod() throws Exception
2 注意事项
1、由于retry用到了aspect增强,所以在方法内部调用,会使aspect增强失效,那么retry当然也会失效。
示例:
public class RetryService {
public void method1() {
method2();//内部调用retry会失效
}
@Retryable(Exception.class)
public void method2() {
throw new RuntimeException("这里出现异常,该方法需要重试....");
}
}
2、很多地方都说不能在接口的实现类上使用这个注解,是错误的,目标方法不能有返回值,也是错误的,亲测有效哈(下面的demo就以在接口的实现类中使用@Retryable进行展示),当然也可以自行去写demo试一试。
我引进来之后的版本是
其它版本自行测试一遍。
3、被重试的目标方法所在的类必须配置为spring的bean
4、spring retry的重试机制是同步进行的,不是异步
3 简单的示例
1、重试目标(接口和实现类(可以映射为生成环境的service层))
--接口
public interface IRetryService {
String targetMethod() throws Exception;
}
--实现类
@Component
public class RetryServiceImpl implements IRetryService {
@Retryable(Exception.class)
@Override
public String targetMethod() throws Exception {
System.out.println("目标被调用");
Random random = new Random();
int i = random.nextInt(10);
if (i > 1) {
throw new NullPointerException("大于1");
}
return "小于或等于1";
}
}
2、配置类(一定要将重试目标交给IoC管理)
@Configuration
@EnableRetry//开启重试功能,springboot项目可作用于启动类上
public class RetryConfig {
@Bean(name="retryServiceImpl")
public RetryServiceImpl initRetryService() {
return new RetryServiceImpl();
}
}
3、测试类及结果
@RunWith(SpringRunner.class)
@SpringBootTest
public class RetryServiceTest {
@Autowired
private IRetryService iRetryService;
@Test
public void methodA() {
try {
String result = iRetryService.targetMethod();
System.out.println("test-->" + result);
} catch (Exception e) {
System.out.println("目标方法异常....");
}
}
}
----------------------------------------------------------------------
目标被调用
目标被调用
目标被调用
test-->小于或等于1
说明
可以明显的看到,目标方法被重试了3次(多次运行测试类结果不一定相同的,但是一旦目标方法产生指定的异常,则进行重试,有可能重试之后,得到了一个异常,但是,不管怎么运行测试方法,最多只重试了3次)。
4 @Retryable注解和@Recover注解常用属性详解
1 @Recover注解
—>value属性:Throwable子类的Class数组,指定发生具体的异常进行重试,默认是所有异常都重试;
—>include属性:同value属性;
—>exclude属性:指定不处理的异常,Throwable子类的Class数组;
—>maxAttemps:最大尝试次数(包括第一次失败)默认为3次;
—>backoff:重试补偿机制,默认没有
2 @Backoff注解
—>delay:指定延迟后重试,默认为1000L,即1s后开始重试 ;
—>multiplier:指定延迟的倍数,默认为0,比如delay=5000l,multiplier=2时,第一次重试为5秒后,第二次为10秒,第三次为20秒;
—>maxDelay:重试次数之间的最大时间间隔,默认为0,即忽略,如果小于delay的设置,则默认为30000L;
3 @Recover 注解
指定回调函数。
当重试耗尽时,Spring-Retry还提供了@Recover注解,用于@Retryable重试失败后处理方法,此方法里的异常一定要是@Retryable方法里抛出的异常,否则不会调用这个方法。
--重试耗尽后的回调函数,注意异常类型一定要是目标方法抛出的异常类型
@Recover
public int recover(Exception e) {
// do something...
return 0;
}
5 简单的完整示例
这是注解最全的一个示例了,如果想要完整的实例,结合第三章一起看就行了
@Retryable(value= {Exception.class}, maxAttempts=4, backoff=@Backoff(delay = 1000l,maxDelay = 10 * 1000L, multiplier = 1))
public String targetMethod() throws Exception ();
说明:指定Exception及其子类的重试异常;最大重试次数为4;首次重试间隔1000ms;每次重试间隔10*1000ms;延迟倍数为1,即每次间隔为1000ms。