一、@Retryable注解
注解方式实现重试机制比较简单,只需要我们在需要重试的方法上加入以下注解
@Retryable(value = {RemoteAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))
- value:指定需要重试的异常类型。在这个例子中,我们指定了 RemoteAccessException 类型的异常。
- maxAttempts:指定最大重试次数。在这个例子中,我们指定了最大重试次数为 3。
- backoff:指定重试之间的时间间隔。在这个例子中,我们指定了 1000 毫秒的时间间隔。
当然异常类型可以写成Exception.class,这样当方法抛出任何异常都会重试了。
使用注解的方式实现重试机制需要注意以下几点:
1.首先是启动类加上@EnableReTry注解
2. 要求需要重试的方法和调用它的方法不能同属一个类中,因为@Retryable注解是通过切面实现的,说白了就是带有@Retryable注解的方法和调用他的方法都要被spring管理,属于不同的类即可。
3.@Retryable只能实现重试机制,重试次数达到上限后,还是失败,此时如果有需要回调处理的逻辑,需要另外一个注解@Recover
@Retryable(value = {SQLException.class}, maxAttempts = 3, backoff = @Backoff(delay = 100))
public void myMethod() throws SQLException {// Some database operation that may throw a SQLException
}@Recover
public void recover(SQLException e) {// Recovery logic goes here
}
要求@Retryable
和@Recover
必须定义在一个类当中,这一点和上面调用@Retryable的方法必须分属不同的类正好相反,同时也要求@Retryable注解的方法不能有返回值,否则@Recover不生效
那如果一个类中有多个@Recover和@Retryable怎么区分?
很简单,可以通过value
属性来区分它们。value
属性允许您指定一个异常类型的数组,以区分在方法执行期间抛出的不同异常类型。
具体示例如下:
@Service
public class MyService {
@Retryable(value = {IOException.class})
public void methodA() throws IOException {
// Some code that may throw an IOException
}
@Recover
public void recoverA(IOException e) {
// Recovery logic for methodA() goes here
}
@Retryable(value = {NullPointerException.class})
public void methodB() throws NullPointerException {
// Some code that may throw a NullPointerException
}
@Recover
public void recoverB(NullPointerException e) {
// Recovery logic for methodB() goes here
}
}
笔者不想再单独写类了,想让调用@Retryable注解的方法和带有@Retryable注解本身的方法,两个方法属于一个类中,但是此时@Retryable不生效了,所以搜寻了另外一种方式,通过编码方法实现方法重试,当然也是spring提供的工具了,自己封装也不是不行,就是没那么好,考虑的不全面,请看第二种方式。
二、通过RetryTemplate
这种方式也是要求在启动类上添加@EnableReTry注解,如上图所示
1.RetryTemplate的配置类
package com.ruoyi.maintenance.thirdinterface.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;/*** 重试配置类* @author hulei*/
@Configuration
@EnableRetry
public class RetryConfiguration {@Beanpublic RetryTemplate retryTemplate() {SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();//最大重试次数retryPolicy.setMaxAttempts(5);ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();//倍数backOffPolicy.setMultiplier(2);//初始间隔backOffPolicy.setInitialInterval(3000);RetryTemplate template = new RetryTemplate();template.setRetryPolicy(retryPolicy);template.setBackOffPolicy(backOffPolicy);return template;}
}
配置类主要是设置一些重试次数和重试时间等参数
2.重试代码
我要重试的方法如下图
调用它的方法如下
引入retryTemplate
主要代码片段
try{String result = retryTemplate.execute(//RetryCallback,需要重试的业务逻辑(RetryCallback<String, Throwable>) retryContext -> doPost(url, rsaEncryptHandle(jsonHandle(jsonObject,loop,platform).toJSONString())),//RecoveryCallback兜底,多次重试失败后的处理逻辑,取最后一次重试抛出的异常信息,抛出异常retryContext -> {log.error("删除设备推送接口多次重试调用失败");throw new RuntimeException(retryContext.getLastThrowable().getMessage());});log.info("删除设备远程调用返回结果:{}",result);}catch (Throwable e){log.error("删除远程调用异常:{}",e.getMessage());}
核心是retryTemplate.excute调用
有两个参数RetryCallback和RecoveryCallback
1.RetryCallback
包装需要重试的逻辑,比较简单就是调用了我需要重试的方法doPost()
2.RecoveryCallback
重试次数达到上限,任然没有成功时的回调方法
笔者这里只是打印了并抛出了异常信息,如果有其他需要处理的异常回调逻辑,单独写一个方法,在这里调用即可。
总结:两种方式各有好处,看个人选择,如果需要编写的重试方法较多,建议使用注解方式,省时省力,单一场景使用,不想再写过多的类,使用第二种编码的方式