<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.11.5</version>
</dependency>
这里是在aop的基础上使用自定义注解,对需要进行加锁的业务进行环绕通知。共需要用到一个redisson工具类、自定义注解类、Aop通知逻辑、业务测试类,分别如下。
1、redisson工具类
@Component
public class RedisLockUtils {
@Autowired
private RedissonClient redissonClient;
/**
* 可重入,!线程不主动解锁将会永远存在! 慎用
*/
public void lock(String lockKey){
RLock lock = redissonClient.getLock(lockKey);
redissonClient.getRedLock(lock).lock();
}
public void lock(String lockKey, Runnable runnable){
lock(lockKey);
try {
runnable.run();
} finally {
this.unLock(lockKey);
}
}
/**
* 拿到索 并设置一个超时时间
* @param lockKey
* @param leaseTime
*/
public void lock(String lockKey, long leaseTime) {
RLock lock1 = redissonClient.getLock(lockKey);
redissonClient.getRedLock(lock1).lock(leaseTime, TimeUnit.MILLISECONDS);
}
public void lock(String lockKey, long leaseTime, Runnable runnable) {
lock(lockKey, leaseTime);
try {
runnable.run();
} finally {
this.unLock(lockKey);
}
}
/**
* 在一定时间内获取某个锁 并且设置锁的超时时间
* @param lockKey 锁
* @param waitTime 争夺所的时间段
* @param leaseTime 锁的超时时间
* @return
* @throws InterruptedException
*/
public boolean tryLockTimeout(String lockKey,long waitTime, long leaseTime) throws InterruptedException {
RLock lock1 = redissonClient.getLock(lockKey);
return redissonClient.getRedLock(lock1).tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS);
}
public boolean tryLockTimeout(String lockKey, long waitTime, long leaseTime, Runnable runnable) throws InterruptedException {
if (tryLockTimeout(lockKey, waitTime, leaseTime)) {
try {
runnable.run();
} finally {
this.unLock(lockKey);
}
return true;
}
return false;
}
public void unLock(String lockKey) {
RLock lock1 = redissonClient.getLock(lockKey);
redissonClient.getRedLock(lock1).unlock();
}
}
其中redisssonClient注入方式如下
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.password}")
private String password;
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient(){
Config config = new Config();
SingleServerConfig singleServerConfig = config.useSingleServer().setAddress("redis://" + host + ":" + port);
if(StringUtils.isNotBlank(password)){
singleServerConfig.setPassword(password);
}
return Redisson.create(config);
}
2、自定义注解
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 RedisLock {
String lockValue() default "zyht";
}
3、Aop通知逻辑
import com.emergency.common.entity.AjaxResult;
import com.emergency.config.custom_annotation.RedisLock;
import com.emergency.config.util.RedisLockUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class RedisLocAop {
static Logger logger = LoggerFactory.getLogger(RedisLocAop.class);
@Pointcut("@annotation(com.emergency.config.custom_annotation.RedisLock)" )
public void redisLockAdvice(){}
@Autowired
private RedisLockUtils redisLockUtils;
@Around("redisLockAdvice()")
public Object Interceptor(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature msg=(MethodSignature) joinPoint.getSignature();
//拿到注解标注的方法
Method method = joinPoint.getTarget().getClass().getMethod(msg.getName(), msg.getParameterTypes());
//拿到注解
RedisLock annotation = method.getAnnotation(RedisLock.class);
String lockKey = annotation.lockValue();
boolean isLock = false;
try {
//1.拿到锁
//(5000毫秒尝试获取锁, 锁定后10000毫秒锁过期自动释放,最大容差为5000毫秒,注意方法执行时间).
//2.注力度,满足最大容差即可
isLock = redisLockUtils.tryLockTimeout(lockKey, 5000, 10000);
//5000毫秒超时未获得锁
if(!isLock ){
return AjaxResult.error("业务繁忙,请重试。");
}
//锁获得后,执行业务
logger.info("执行方法:{},并拿到锁。",joinPoint.getSignature().getName());
Object result = joinPoint.proceed();
return result;
} catch (Exception e) {
logger.error("run error:", e);
return AjaxResult.error("执行方法:{},出现异常。",joinPoint.getSignature().getName());
}finally {
//解锁
if(isLock) {
redisLockUtils.unLock(lockKey);
}
}
}
}
4、用于测试
@Override
@RedisLock(lockValue = "00000001")
public AjaxResult method1() throws InterruptedException {
Thread.sleep(3000);
return AjaxResult.success();
}
@Override
@RedisLock(lockValue = "00000001")
public AjaxResult method2() throws InterruptedException {
Thread.sleep(3000);
return AjaxResult.success();
}









