<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(); }