1 问题说明
spring-retry中的@Recover注解,可在重试失败后会执行注解所在方法中的处理逻辑。如何将传递给@Retryable方法的参数传递给@Recover所标注的方法?
2 解决方式
官方文档中指出,恢复方法的参数可以可选地包括抛出的异常和(可选)传递给原始可重试方法的参数。示例:
@Service
class Service {
@Retryable(RemoteAccessException.class)
public void service(String str1, String str2) {
// ... do something
}
@Recover
public void recover(RemoteAccessException e, String str1, String str2) {
// ... error handling making use of original args if required
}
}
要解决可以选择进行恢复的多个方法之间的冲突,可以显式指定恢复方法名称。示例:
@Service
class Service {
@Retryable(recover = "service1Recover", value = RemoteAccessException.class)
public void service1(String str1, String str2) {
// ... do something
}
@Retryable(recover = "service2Recover", value = RemoteAccessException.class)
public void service2(String str1, String str2) {
// ... do something
}
@Recover
public void service1Recover(RemoteAccessException e, String str1, String str2) {
// ... error handling making use of original args if required
}
@Recover
public void service2Recover(RemoteAccessException e, String str1, String str2) {
// ... error handling making use of original args if required
}
}
1.3.2 及更高版本支持匹配参数化(通用)返回类型以检测正确的恢复方法:
@Service
class Service {
@Retryable(RemoteAccessException.class)
public List<Thing1> service1(String str1, String str2) {
// ... do something
}
@Retryable(RemoteAccessException.class)
public List<Thing2> service2(String str1, String str2) {
// ... do something
}
@Recover
public List<Thing1> recover1(RemoteAccessException e, String str1, String str2) {
// ... error handling for service1
}
@Recover
public List<Thing2> recover2(RemoteAccessException e, String str1, String str2) {
// ... error handling for service2
}
}
3 测试验证
测试代码:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
/**
* <pre>
* 测试@Recover获取参数信息
* </pre>
*
* @author LOOPY_Y
* @since 2022/4/14
*/
@Service
@Slf4j
public class RecoverGetParamService {
@Retryable(value = Exception.class, backoff = @Backoff(delay = 5000, multiplier = 2, maxDelay = 8000))
public Boolean retryMethod(RetryParam retryParam) throws Exception {
log.info("=================== 进入到retryMethod方法 =====================");
String name = retryParam.getName();
if (StringUtils.isBlank(name) || !"小明".equals(name)) {
log.error("retryMethod准备抛出异常");
throw new Exception("retryMethod执行时发生异常");
}
log.info("name为:{} , age为:{}", name, retryParam.getAge());
return true;
}
@Recover
public Boolean retryMethodRecover(Exception e, RetryParam retryParam) {
log.info("=================== 进入到retryMethodRecover方法 =====================");
log.info("retryParam参数值为:{}", retryParam);
log.error("异常信息为:", e);
return false;
}
}
测试结果:如图,可以看到参数信息在Recover中已拿到。