乐观锁失败或接口调用失败后使用AOP实现重试机制

一、乐观锁失败后会报:ObjectOptimisticLockFailureExceptionjava
二、处理方案:捕获到对应乐观锁失败异常后进行重试

以下使用aop实现一个重试,可用于乐观锁
1、新建一个注解,用于标注需要重试的方法

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RetryOnOptimisticLockingFailure {
}

2、新建重试的方法并添加注解

public interface UserService {
    int save();
}

@Service
public class UserServiceImpl implements UserService{
    @Override
    @RetryOnFail  //添加重试注解
    public int save() {
        int i = new Random().nextInt(10);
        int i1 = 10 / (i % 3); //除0异常  这里模拟乐观异常
        return i1;
    }
}

3、新建切面类对标注注解的方法进行代理

@Component
@Aspect
public class RetryOnOptimisticLockingFailureAspect {
    //定义最大重试次数
    private final int MAX_RETRY_TIME=5;
    
    //基于注解定义切入点 --这里要写刚刚定义那个注解的全限定名
    @Pointcut("@annotation(com.example.service.RetryOnOptimisticLockingFailure)")
    public void retryOnOptFailure(){}

    //定义通知
    @Around("retryOnOptFailure()")
    public Object doProceed(ProceedingJoinPoint joinPoint) throws Throwable {
        int time=0;
        do {//循环5次
            time++;
            try {
                Object proceed = joinPoint.proceed();
                return proceed;//如果没有异常则正常返回结束循环与方法
            } catch (Exception e) {
                //出异常了,记录log,进入循环
                if(e instanceof ArithmeticException){//修改对应的异常   如:乐观锁OptimisticLockingException
                    System.out.println("retrying....times:"+time);
                }
            }
        } while (time<MAX_RETRY_TIME);
        return null;
    }
}

4、测试

@SpringBootTest
public class MyTest {
    @Autowired
    private UserService userService;

    @Test
    public void save(){
        for (int i = 0; i < 10; i++) {//调用10次  增加触发重试的机率
            System.out.println(userService.save());
        }
    }
}

5、运行结果

在这里插入图片描述

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP可以使用AspectJ注解来实现接口重复调用的拦截。假设我们有一个接口`UserService`,其中有一个`saveUser`方法,我们希望在该方法被调用时进行拦截,防止重复调用。我们可以定义一个切面类`DuplicateInvokeAspect`,并为其添加一个`@Around`注解的方法,该方法将拦截`UserService`的`saveUser`方法,并在该方法中添加重复调用判断逻辑。 ``` @Aspect public class DuplicateInvokeAspect { private Map<String, Long> lastInvokeMap = new ConcurrentHashMap<>(); @Around("execution(* com.example.UserService.saveUser(..))") public Object checkDuplicateInvoke(ProceedingJoinPoint joinPoint) throws Throwable { String methodName = joinPoint.getSignature().getName(); if (lastInvokeMap.containsKey(methodName)) { long lastInvokeTime = lastInvokeMap.get(methodName); long currentTime = System.currentTimeMillis(); if (currentTime - lastInvokeTime < 5000) { // 限制5秒内不能重复调用 throw new RuntimeException("不能重复调用" + methodName); } } lastInvokeMap.put(methodName, System.currentTimeMillis()); return joinPoint.proceed(); } } ``` 在上述代码中,我们使用`ConcurrentHashMap`来存储方法名和上一次调用时间的映射关系。在`checkDuplicateInvoke`方法中,我们首先判断该方法是否已经在`lastInvokeMap`中存在,如果存在则判断距离上一次调用的时间是否已经超过了5秒,如果没有超过则抛出异常,否则将当前时间更新为上一次调用时间,并继续执行原有的方法逻辑。 最后,我们需要在Spring配置文件中启用该切面类: ``` <aop:aspectj-autoproxy/> <bean id="duplicateInvokeAspect" class="com.example.DuplicateInvokeAspect"/> ``` 这样就完成了接口重复调用的拦截功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值