From ad6386a618eb81c401333c6541ec798932991bf6 Mon Sep 17 00:00:00 2001 From: sxq <812980466@qq.com> Date: 星期五, 04 六月 2021 15:00:56 +0800 Subject: [PATCH] redis分布式锁(基于注解形势)。 --- ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockAspect.java | 124 ++++++++++++++++++++++++ ruoyi-common/src/main/java/com/ruoyi/common/annotation/RedisLock.java | 27 +++++ ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/RedisLockController.java | 44 ++++++++ ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockUtil.java | 64 ++++++++++++ 4 files changed, 259 insertions(+), 0 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/RedisLockController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/RedisLockController.java new file mode 100644 index 0000000..28102d0 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/RedisLockController.java @@ -0,0 +1,44 @@ +package com.ruoyi.web.controller.system; + +import com.ruoyi.common.annotation.RedisLock; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.domain.model.LoginBody; +import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.framework.web.service.TokenService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +/** + * 娴嬭瘯鍒嗗竷寮忛攣鐨勬牱渚� + */ +@RestController +@RequestMapping("/system/redisLock") +public class RedisLockController { + + @Autowired + private TokenService tokenService; + + /** + * #p0 鏍囪瘑鍙栫涓�涓弬鏁颁负redis閿佺殑key + * @param loginBody + * @return + */ + @GetMapping("/getLock") + @RedisLock(expireTime=10,key = "#p0") + public AjaxResult getInfo(@RequestBody LoginBody loginBody){ + LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); + SysUser user = loginUser.getUser(); + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return AjaxResult.success(user); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RedisLock.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RedisLock.java new file mode 100644 index 0000000..e84f5c8 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RedisLock.java @@ -0,0 +1,27 @@ +package com.ruoyi.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 鍒嗗竷寮忛攣锛堟敞瑙fā寮忥紝涓嶆帹鑽愪娇鐢紝鏈�濂界敤閿佺殑宸ュ叿绫伙級 + */ + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RedisLock { + + /** + * 閿佽繃鏈熸椂闂� + * @return + */ + int expireTime() default 30;//30绉� + + /** + * 閿乲ey鍊� + * @return + */ + String key() default "redisLockKey"; +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockAspect.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockAspect.java new file mode 100644 index 0000000..c249dfe --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockAspect.java @@ -0,0 +1,124 @@ +package com.ruoyi.common.core.redis; + + +import com.ruoyi.common.annotation.RedisLock; +import com.ruoyi.common.utils.file.ImageUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * 鍒嗗竷寮忛攣锛堟敞瑙e疄鐜扮増鏈級 + */ +@Component +@Aspect +@Order(9) +public class RedisLockAspect { + @Autowired + private RedisLockUtil redisUtil; + + private static final Logger log = LoggerFactory.getLogger(RedisLockAspect.class); + + @Pointcut("@annotation(com.ruoyi.common.annotation.RedisLock)") + public void annotationPointcut() { + } + + @Around("annotationPointcut()") + public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { + // 鑾峰緱褰撳墠璁块棶鐨刢lass + Class<?> className = joinPoint.getTarget().getClass(); + // 鑾峰緱璁块棶鐨勬柟娉曞悕 + String methodName = joinPoint.getSignature().getName(); + // 寰楀埌鏂规硶鐨勫弬鏁扮殑绫诲瀷 + Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes(); + Object[] args = joinPoint.getArgs(); + String key = ""; + // 榛樿30绉掕繃鏈熸椂闂� + int expireTime = 30; + try { + // 寰楀埌璁块棶鐨勬柟娉曞璞� + Method method = className.getMethod(methodName, argClass); + method.setAccessible(true); + // 鍒ゆ柇鏄惁瀛樺湪@RedisLock娉ㄨВ + if (method.isAnnotationPresent(RedisLock.class)) { + RedisLock annotation = method.getAnnotation(RedisLock.class); + key = getRedisKey(args, annotation.key()); + expireTime = getExpireTime(annotation); + } + } catch (Exception e) { + throw new RuntimeException("redis鍒嗗竷寮忛攣娉ㄨВ鍙傛暟寮傚父", e); + } + Object res = new Object(); + if (redisUtil.acquire(key, expireTime, TimeUnit.SECONDS)) { + try { + res = joinPoint.proceed(); + return res; + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + redisUtil.release(key); + } + }else { + throw new RuntimeException("redis鍒嗗竷寮忛攣娉ㄨВ鍙傛暟寮傚父"); + } + } + + private int getExpireTime(RedisLock annotation) { + return annotation.expireTime(); + } + + private String getRedisKey(Object[] args, String primalKey) { + if (args.length == 0) { + return primalKey; + } + // 鑾峰彇#p0...闆嗗悎 + List<String> keyList = getKeyParsList(primalKey); + for (String keyName : keyList) { + int keyIndex = Integer.parseInt(keyName.toLowerCase().replace("#p", "")); + Object parValue = args[keyIndex]; + primalKey = primalKey.replace(keyName, String.valueOf(parValue)); + } + return primalKey.replace("+", "").replace("'", ""); + } + + /** + * 鑾峰彇key涓�#p0涓殑鍙傛暟鍚嶇О + * + * @param key + * @return + */ + private static List<String> getKeyParsList(String key) { + List<String> listPar = new ArrayList<>(); + if (key.contains("#")) { + int plusIndex = key.substring(key.indexOf("#")).indexOf("+"); + int indexNext = 0; + String parName; + int indexPre = key.indexOf("#"); + if (plusIndex > 0) { + indexNext = key.indexOf("#") + key.substring(key.indexOf("#")).indexOf("+"); + parName = key.substring(indexPre, indexNext); + } else { + parName = key.substring(indexPre); + } + listPar.add(parName.trim()); + key = key.substring(indexNext + 1); + if (key.contains("#")) { + listPar.addAll(getKeyParsList(key)); + } + } + return listPar; + } + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockUtil.java new file mode 100644 index 0000000..6dc6591 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockUtil.java @@ -0,0 +1,64 @@ +package com.ruoyi.common.core.redis; + + +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +@Component +public class RedisLockUtil { + + @Autowired + private RedissonClient redissonClient; + + private static final String LOCK_TITLE = "redisLock_"; + + private static final Logger log = LoggerFactory.getLogger(RedisLockUtil.class); + +/* public boolean getLock(String key){ + key = LOCK_TITLE + key; + RLock mylock = redissonClient.getLock(key); + System.err.println("======lock======" + Thread.currentThread().getName()); + return true; + }*/ + + /** + * 鍔犻攣 锛圧Lock锛夊甫瓒呮椂鏃堕棿鐨� + * @param key + * @param expire + * @param expireUnit + * @return + */ + public boolean acquire(String key, long expire, TimeUnit expireUnit) { + //澹版槑key瀵硅薄 + key = LOCK_TITLE + key; + //鑾峰彇閿佸璞� + RLock mylock = redissonClient.getLock(key); + //鍔犻攣锛屽苟涓旇缃攣杩囨湡鏃堕棿锛岄槻姝㈡閿佺殑浜х敓 + try { + mylock.tryLock(expire,expire,expireUnit); + } catch (InterruptedException e) { + e.getMessage(); + return false; + } + System.err.println("======lock======" + Thread.currentThread().getName()); + //鍔犻攣鎴愬姛 + return true; + } + //閿佺殑閲婃斁 + public void release(String lockName) { + //蹇呴』鏄拰鍔犻攣鏃剁殑鍚屼竴涓猭ey + String key = LOCK_TITLE + lockName; + //鑾峰彇鎵�瀵硅薄 + RLock mylock = redissonClient.getLock(key); + //閲婃斁閿侊紙瑙i攣锛� + mylock.unlock(); + System.err.println("======unlock======" + Thread.currentThread().getName()); + } + +} -- Gitblit v1.9.3