前言
在程序查询接口时,有时执行中会出现错误,包括一些未知错误,这些错误本身是软件本身的错误,比如数据库的底层错误,我们无法解决这些错误,这时会因为这些原因导致请求失败,此时我们希望能够自动重试该请求,以提高系统的可靠性和稳定性。
解决方案
在AOP切面中@Around环绕通知方法增加重试机制
@Aspect
@Component
public class WebLogAspect {
private final static Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
private static final String BAD_SQL_GRAMMAR_EXCEPTION = "org.springframework.jdbc.BadSqlGrammarException";
private static final String UNKNOWN_ERROR = "Unknown error";
@Pointcut("execution(public * xxx.xxx.xxx.xxx.controller..*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 打印请求相关参数
logger.info("{\"Request_Detail\":{" +
"\"URL\":\"{}\"," +
"\"HTTP_Method\":\"{}\"," +
"\"Class_Method\":\"{}.{}\"," +
"\"IP\":\"{}\"" +
"}}",
request.getRequestURL().toString(),
request.getMethod(),
joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(),
request.getRemoteAddr()
);
// 打印请求入参
logger.info("{\"Request_Args\":{}}", JSON.toJSON(joinPoint.getArgs()));
}
@Around("pointcut()")
public Object Around(ProceedingJoinPoint point) throws Throwable {
int maxRetryNum = 3;//重试最大次数
int nowRetryNum = 0;//当前重试次数
Throwable lastException;//记录最后异常
do {
nowRetryNum++;
try {
Object proceed = point.proceed();//切点方法
// 打印出参
logger.info("{\"Response_Args\":{}}", JSON.toJSON(proceed));
return proceed;
} catch (Throwable e) {
lastException = e;
String exceptionName = e.getClass().getName();//获取异常类名
String detailMessage = e.getCause() == null ? e.getMessage() : e.getCause().getMessage();//获取异常具体消息
//判断是否为SR查询异常
if (!BAD_SQL_GRAMMAR_EXCEPTION.equals(exceptionName) || StringUtils.isEmpty(detailMessage) || !detailMessage.contains(UNKNOWN_ERROR)) {
//停止请求重试
nowRetryNum = maxRetryNum + 1;
} else {
//重试日志打印
logger.warn("{\"Request_Retry\"{}\"\":{" +
"\"Exception_Name\":\"{}\"," +
"\"Exception_Message\":\"{}\"" +
"}}",
nowRetryNum,
e.getClass().getName(),
e.getMessage()
);
}
}
} while (nowRetryNum <= maxRetryNum);
throw lastException;
}
}