redis+aop防重复提交
生活随笔
收集整理的這篇文章主要介紹了
redis+aop防重复提交
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1.防重復提交注解
- 2.redis分布式鎖
- 3.防止重復提交Aop
之前有記錄一篇用redis+攔截器防重復提交的內容:
redis+攔截器防重復提交
1.防重復提交注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface NoRepeatSubmit {/*** 設置請求鎖定時間** @return*/int lockTime() default 10;}2.redis分布式鎖
/*** Redis 分布式鎖實現*/ @Service public class RedisLock {private static final Long RELEASE_SUCCESS = 1L;private static final String LOCK_SUCCESS = "OK";private static final String SET_IF_NOT_EXIST = "NX";// 當前設置 過期時間單位, EX = seconds; PX = millisecondsprivate static final String SET_WITH_EXPIRE_TIME = "EX";// if get(key) == value return del(key)private static final String RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";@Autowiredprivate StringRedisTemplate redisTemplate;/*** 該加鎖方法僅針對單實例 Redis 可實現分布式加鎖* 對于 Redis 集群則無法使用* <p>* 支持重復,線程安全** @param lockKey 加鎖鍵* @param clientId 加鎖客戶端唯一標識(采用UUID)* @param seconds 鎖過期時間* @return*/public boolean tryLock(String lockKey, String clientId, int seconds) {return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {Jedis jedis = (Jedis) redisConnection.getNativeConnection();String result = jedis.set(lockKey, clientId, SetParams.setParams().nx().ex(seconds));if (LOCK_SUCCESS.equals(result)) {return true;}return false;});} //redisTemplate.execute的源碼: // public <T> T execute(RedisCallback<T> action) { // return execute(action, isExposeConnection());//}/*** 與 tryLock 相對應,用作釋放鎖** @param lockKey* @param clientId* @return*/public boolean releaseLock(String lockKey, String clientId) {return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {Jedis jedis = (Jedis) redisConnection.getNativeConnection();Object result = jedis.eval(RELEASE_LOCK_SCRIPT, Collections.singletonList(lockKey),Collections.singletonList(clientId));if (RELEASE_SUCCESS.equals(result)) {return true;}return false;});} }3.防止重復提交Aop
//yixiangshangcheng @Aspect @Component @Slf4j public class RepeatSubmitAspect {@Autowiredprivate RedisLock redisLock;@Pointcut("@annotation(noRepeatSubmit)")public void pointCut(NoRepeatSubmit noRepeatSubmit) {}@Around("pointCut(noRepeatSubmit)")public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) throws Throwable {int lockSeconds = noRepeatSubmit.lockTime();HttpServletRequest request = RequestHolder.getHttpServletRequest();Assert.notNull(request, "request can not null");String bearerToken = request.getHeader("Authorization");String[] tokens = bearerToken.split(" ");String token = tokens[1];String path = request.getServletPath();String key = getKey(token, path);String clientId = getClientId();boolean isSuccess = redisLock.tryLock(key, clientId, lockSeconds);log.info("tryLock key = [{}], clientId = [{}]", key, clientId);if (isSuccess) {log.info("tryLock success, key = [{}], clientId = [{}]", key, clientId);// 獲取鎖成功Object result;try {// 執行進程result = pjp.proceed();} finally {// 解鎖redisLock.releaseLock(key, clientId);log.info("releaseLock success, key = [{}], clientId = [{}]", key, clientId);}return result;} else {// 獲取鎖失敗,認為是重復提交的請求log.info("tryLock fail, key = [{}]", key);///return ApiResult.fail("重復請求,請稍后再試");throw new BadRequestException("重復請求,請稍后再試");}}private String getKey(String token, String path) {return token + path;}private String getClientId() {return UUID.randomUUID().toString();}}之后在Contoller方法上加 @NoRepeatSubmit即可。
總結
以上是生活随笔為你收集整理的redis+aop防重复提交的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自定义线程池内置线程池的使用 Threa
- 下一篇: springboot使用Template