自定义注解

1 重试注解

(1)定义重试注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RetryAnnotation {

    int retryTimes() default 0 ;

    /**
     * 重试策略
     * @return
     */
    MidBackoff backoff() default @MidBackoff();
}

(2)重试切面

@RefreshScope
@Component
@Aspect
@Slf4j
public abstract class RetryAspect {

    @Resource
    private RetryTemplate retryTemplate;

    @Value("${system.config.cluster:normal}")
    private String env;

    @Value("${myj.env.groupId}")
    private String groupId;

    @Value("${myj.env.cluster}")
    private String envConfig;

    @Pointcut("@annotation(com.sr.bizmid.tradeCore.common.annotation.RetryAnnotation)")
    public void pointCut() {
    }

    @Around("pointCut() && @annotation(retryAnnotation)")
    public Object process(ProceedingJoinPoint joinPoint, RetryAnnotation retryAnnotation) throws Throwable {
        AtomicReference<Object> proceed = new AtomicReference<>();
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        Class targetClass = signature.getDeclaringType();
        final Object[] args = joinPoint.getArgs();
        try {
            retryTemplate.execute(context -> {
                try {
                      proceed.set(joinPoint.proceed());
                } catch (Exception e) {
                    log.error("RetryAspect retryError className:{}  method:{} args:{}",targetClass.getName(),name, JSON.toJSONString(args),e);
                    throw e;
                }
                return null;
            });

        } catch (Exception e) {
            log.error("RetryAspect retryFinishError className:{}  method:{} args:{}",targetClass.getName(),name,JSON.toJSONString(args),e);
            //加入重试表重试
            saveRetryRecord(joinPoint, retryAnnotation);
            throw new TRetailSystemException(TradeBaseErrorCode.TRADE_CORE_RETRY_ASPECT_ERROR,e);
        }
        return proceed.get();
    }

    private void saveRetryRecord(ProceedingJoinPoint joinPoint, RetryAnnotation retryAnnotation){
        try {
            Date date = new Date();
            BizRetry bizRetry = new BizRetry();
            bizRetry.setCreateTime(date);
            bizRetry.setUpdateTime(date);
            bizRetry.setOperableTime(date);
            bizRetry.setStatus((byte) 0);
            bizRetry.setIsDeleted(isAbandon() ? (byte) 1 : (byte) 0);//加上开关
            bizRetry.setRetriedCount(0);
            bizRetry.setMethodName(joinPoint.getSignature().getName());
            bizRetry.setClassName(joinPoint.getSignature().getDeclaringType().getName());

            MidBackoff backoff = retryAnnotation.backoff();
            BizRetry.MidBackoff midBackoff = new BizRetry.MidBackoff();
            midBackoff.setCount(backoff.count());
            midBackoff.setDelay(backoff.delay());
            midBackoff.setMultiplier(backoff.multiplier());

            bizRetry.setBackoff(midBackoff);

            int delay = backoff.delay();
            if (backoff.multiplier() > 0d) {
                delay = (int) ((double) delay * backoff.multiplier());
            }
            bizRetry.setOperableTime(add(date, Calendar.SECOND, delay));

            Object[] args = joinPoint.getArgs();
            List<String> argsList = new ArrayList<>(args.length);
            List<String> types = new ArrayList<>();
            Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();

            for (Class clazz : parameterTypes) {
                types.add(clazz.getName());
            }

            for (Object arg : args) {
                argsList.add(JSON.toJSONString(arg));
            }

            // 参数列表类型
            bizRetry.setArgsTypes(JSON.toJSONString(types));
            // 参数
            bizRetry.setArgs(JSON.toJSONString(argsList));

            // 保存重试记录
            saveRetryRecord(bizRetry);
        }catch (Throwable t){
            LoggerUtils.fmtError(log,t,"saveRetryRecord新增重试记录异常");
        }
    }

    /**
     * 返回true拦截,false不拦截
     * @return
     */
    private boolean isAbandon() {
        boolean result;
        try {
            String appId = TsrSpringContextAware.getApplicationContext().getEnvironment().getProperty("tsf_group_id");
            // 匹配过滤的环境
            result = groupId.equals(appId) && envConfig.equals(env);
        } catch (Exception e) {
            result = false;
        }
        return result;
    }

    private Date add(Date date, int calendarField, int amount) {
        if (date == null) {
            throw new IllegalArgumentException("The date must not be null");
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(calendarField, amount);
        return c.getTime();
    }

    public abstract void saveRetryRecord(BizRetry bizRetry);

}



(3)RPC 调用使用重试注解

    @RetryAnnotation(backoff = @MidBackoff(count = 5,multiplier = 1,delay = 30))
    public void writeOFFCoupon(String orderNo, String uid, Long rootSaasId, Long saasId, String userName, List<String> codes){
        OperateCouponsRequest operateCouponsRequest = new OperateCouponsRequest();
        operateCouponsRequest.setRequestId(uid + System.currentTimeMillis());
        operateCouponsRequest.setBizId(rootSaasId);
        operateCouponsRequest.setSubSaasId(saasId);
        operateCouponsRequest.setOperator(userName);
        operateCouponsRequest.setFunc(OperateCouponFuncEnum.WRITE_OFF.getFunc());
        operateCouponsRequest.setCodes(codes);
        operateCouponsRequest.setUserId(uid);
        operateCouponsRequest.setUseSceneId(UseChannelEnum.ONLINE.getChannel().toString());
        operateCouponsRequest.setUseTransactionId(orderNo);
        HttpResult<Boolean> httpResult;
        try {
            log.info("调用核销优惠券请求入参:{}", JSON.toJSONString(operateCouponsRequest));
            httpResult = couponClient.operateCoupons(operateCouponsRequest);
            log.info("调用核销优惠券请求response:{}", JSON.toJSONString(httpResult));
        }catch (Exception e) {
            throw new TRetailRpcResultException(TradeRpcErrorCode.TRADE_CALL_COUPON_ERROR, e);
        }
        if (!httpResult.isSuccess() || httpResult.getData() == null) {
            throw new TRetailRpcResultException(TradeRpcErrorCode.TRADE_CALL_COUPON_ERROR);
        }
    }

上一篇:mysql存储过程快速入门


下一篇:SQL2005清空删除日志