Java幂等性实现(Redis+AOP)

什么是幂等?

在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现。 ——来自百度百科

通俗的讲:
同一个系统,同一个接口方法,相同的参数执行多次,得到的结果都是一样的。

幂等解决的场景

如果某些场景接口方法重复执行的话,系统就会出现预想不到的后果,如:

  • 前端信息多次提交
  • 消息服务多次触发
  • 系统对接外部接口等

应对这些场景时,幂等性就尤为重要了。

接口幂等实现方案(Redis+AOP)

实现思路:

  • 设置注解redis过期时间;
  • 通过AOP切面,拦截请求;
  • 每次执行请求时,将接口加密信息保存至redis数据库中;
  • 插入数据成功则请求成功;
  • 否则拦截此次请求。

代码实现:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Idempotent {
    /**
     * 过期时间 毫秒
     */
    long expireMillis();
}
@Aspect
@Component
@Slf4j
@ConditionalOnClass(RedisTemplate.class)
public class IdempotentAspect{

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    private static final String KEY_FORMAT = "idempotentSubmit:%s";

    @Pointcut("@annotation(com.test.anno.Idempotent)")
    public void execute(){}

    @Around("execute()")
    @SneakyThrows
    public Object around(ProceedingJoinPoint joinPoint) {
        Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();
        Idempotent annotation = method.getAnnotation(Idempotent.class);
        if (Objects.isNull(annotation)) {
            return joinPoint.proceed();
        }
        String key = getKeyString(joinPoint, method);
        String redisKey = MD5Util.string2MD5(key);
        Boolean b = redisTemplate.opsForValue().setIfAbsent(redisKey, redisKey);
        if (b != null && b) {
            redisTemplate.expire(redisKey,annotation.expireMillis(), TimeUnit.MILLISECONDS);
            return joinPoint.proceed();
        }else {
            throw new RuntimeException("您操作的太快,请稍后再试");;
        }
    }

    private String getKeyString(ProceedingJoinPoint joinPoint, Method method) {
        Object[] args = joinPoint.getArgs();
        StringBuilder builder = new StringBuilder(method.getName()+"-");
        for (Object arg : args) {
            //针对请求参数不为空才去处理
            if (arg != null) {
                if (arg instanceof HttpSession) {
                    HttpSession session = (HttpSession) arg;
                    String email = (String) session.getAttribute("email");
                    builder.append(email).append("-");
                }else {
                    builder.append(MD5Util.string2MD5(arg.toString())).append("-");
                }
            }
        }
        return String.format(KEY_FORMAT,builder.deleteCharAt(builder.length() - 1).toString());
    }
}
@RestController
@RequestMapping("/idempotent")
@Slf4j
public class IdempotentController {

	@Idempotent(key = "/testIdempotent", expireMillis = 2000, desc = "测试")
    @GetMapping("/testIdempotent")
    public String testIdempotent(){
        return "hello";
    }
}
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
幂等性指的是对同一个操作进行多次请求,最终的结果应该是一致的。在Java中,可以通过以下步骤来实现一个幂等性工具: 1. 定义一个唯一标识符,用于标识每个请求的唯一性,可以使用UUID或者请求参数的组合等方式生成。 2. 在请求开始时,先使用唯一标识符检查是否已经处理过该请求,如果已经处理过,则直接返回之前的结果,否则继续处理。 3. 在请求处理完成后,将该请求的唯一标识符存储到一个可持久化的存储介质中,比如数据库、缓存或者文件等。 4. 如果请求处理失败,则需要清除该请求的唯一标识符,以便下次请求可以重新处理。 5. 可以对该工具进行封装,提供给其他模块使用,比如在Controller层或者Service层使用该工具进行幂等性校验。 下面是一个简单的示例代码: ``` public class IdempotencyUtil { private static final String PREFIX = "idempotency:"; public static boolean isProcessed(String requestId) { // check if the request has been processed return RedisUtil.get(PREFIX + requestId) != null; } public static void markProcessed(String requestId) { // mark the request as processed RedisUtil.set(PREFIX + requestId, "processed"); } public static void clear(String requestId) { // clear the request id after processing RedisUtil.del(PREFIX + requestId); } } ``` 在使用该工具时,可以在Controller层或者Service层中先调用isProcessed方法进行幂等性校验,如果返回true,则直接返回之前的结果,否则继续处理请求并在处理完成后调用markProcessed方法标记请求已经处理过。如果处理失败,则需要调用clear方法清除请求标识符以便下次可以重新处理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值