赞
踩
在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现。 ——来自百度百科
通俗的讲:
同一个系统,同一个接口方法,相同的参数执行多次,得到的结果都是一样的。
如果某些场景接口方法重复执行的话,系统就会出现预想不到的后果,如:
应对这些场景时,幂等性就尤为重要了。
@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";
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。