参考
环境
- springcloud
- redisson3.16.1
- redis
- docker
常见分布式锁方案对比
而redisson保持了简单易用、支持锁重入、支持阻塞等待、Lua脚本原子操作
实现
依赖
<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.1</version>
</dependency>
NoRepeatSubmit
package org.example.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 作用到方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时有效
public @interface NoRepeatSubmit {
int timeout() default 3000;
String key() default "";
}
NoRepeatSubmitAop
package org.example.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.example.annotation.NoRepeatSubmit;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
@Slf4j
public class NoRepeatSubmitAop {
@Autowired
private RedissonClient redissonClient;
@Around("execution(* org.example..*Controller.*(..)) && @annotation(nrs)")
public Object arround(ProceedingJoinPoint pjp, NoRepeatSubmit nrs) {
String key = nrs.key();
RLock rLock = redissonClient.getLock(key);
Object obj = null;
try {
boolean isLock = rLock.tryLock(0,nrs.timeout(), TimeUnit.SECONDS);
if (isLock) {
obj = pjp.proceed();
}
} catch (Throwable e) {
e.printStackTrace();
log.error("验证重复提交时出现未知异常!");
return null;
}finally {
if(rLock.isHeldByCurrentThread()){ // 时候是当前执行线程的锁
rLock.unlock(); // 释放锁
}
}
return obj;
}
}