您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何使用自定義注解實(shí)現(xiàn)redisson分布式鎖”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“如何使用自定義注解實(shí)現(xiàn)redisson分布式鎖”吧!
package com.example.demo.annotation; import java.lang.annotation.*; /** * desc: 自定義 redisson 分布式鎖注解 * * @author: 邢陽(yáng) * @mail: xydeveloper@126.com * @create 2021-05-28 16:50 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface Lock { /** * 鎖的key spel 表達(dá)式 * * @return */ String key(); /** * 持鎖時(shí)間 * * @return */ long keepMills() default 20; /** * 沒有獲取到鎖時(shí),等待時(shí)間 * * @return */ long maxSleepMills() default 30; }
package com.example.demo.utils; import com.example.demo.annotation.Lock; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.stereotype.Component; import java.util.Objects; import java.util.concurrent.TimeUnit; /** * desc: 解析 自定義 redisson 分布式鎖注解 * * @author: 邢陽(yáng) * @mail: xydeveloper@126.com * @create 2021-05-28 16:50 */ @Aspect @Component public class LockAspect { @Autowired private RedissonClient redissonClient; /** * 用于SpEL表達(dá)式解析. */ private final SpelExpressionParser spelExpressionParser = new SpelExpressionParser(); /** * 用于獲取方法參數(shù)定義名字. */ private final DefaultParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer(); @Around("@annotation(com.example.demo.annotation.Lock)") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Object object = null; RLock lock = null; try { // 獲取注解實(shí)體信息 Lock lockEntity = (((MethodSignature) proceedingJoinPoint.getSignature()).getMethod()) .getAnnotation(Lock.class); // 根據(jù)名字獲取鎖實(shí)例 lock = redissonClient.getLock(getKeyBySpeL(lockEntity.key(), proceedingJoinPoint)); if (Objects.nonNull(lock)) { if (lock.tryLock(lockEntity.maxSleepMills(), lockEntity.keepMills(), TimeUnit.SECONDS)) { object = proceedingJoinPoint.proceed(); } else { throw new RuntimeException(); } } } finally { if (Objects.nonNull(lock) && lock.isHeldByCurrentThread()) { lock.unlock(); } } return object; } /** * 獲取緩存的key * * key 定義在注解上,支持SPEL表達(dá)式 * * @return */ public String getKeyBySpeL(String spel, ProceedingJoinPoint proceedingJoinPoint) { MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature(); String[] paramNames = defaultParameterNameDiscoverer.getParameterNames(methodSignature.getMethod()); EvaluationContext context = new StandardEvaluationContext(); Object[] args = proceedingJoinPoint.getArgs(); for (int i = 0; i < args.length; i++) { context.setVariable(paramNames[i], args[i]); } return String.valueOf(spelExpressionParser.parseExpression(spel).getValue(context)); } }
/** * desc: 鎖 * * @author: 邢陽(yáng) * @mail: xydeveloper@126.com * @create 2021-05-28 17:58 */ @Service public class LockService { @Lock(key = "#user.id", keepMills = 10, maxSleepMills = 15) public String lock(User user) { System.out.println("持鎖"); return ""; } }
分布式架構(gòu)一定會(huì)用到分布式鎖。目前公司使用的基于redis的redisson分布式鎖。
1.訂單修改操作,首先要獲取該訂單的分布式鎖,能取到才能去操作。lockey可以是訂單的主鍵id。
2.庫(kù)存操作,也要按照客戶+倉(cāng)庫(kù)+sku維護(hù)鎖定該庫(kù)存,進(jìn)行操作。
代碼:
public class RedissonManager { private static RedissonClient redisson; static { Config config = new Config(); config.useSentinelServers() .addSentinelAddress("redis://127.0.0.1:26379","redis://127.0.0.1:7301", "redis://127.0.0.1:7302") .setMasterName("mymaster") .setReadMode(ReadMode.SLAVE) .setTimeout(10000).setDatabase(0).setPassword("123***"); redisson = Redisson.create(config); } /** * 獲取Redisson的實(shí)例對(duì)象 * @return */ public static RedissonClient getRedisson(){ return redisson;} }
import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import java.util.concurrent.TimeUnit; public class DistributedLock { private static RedissonClient redissonClient = RedissonManager.getRedisson(); public static boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) { RLock lock = redissonClient.getLock(lockKey); try { return lock.tryLock(waitTime, leaseTime, unit); } catch (InterruptedException e) { return false; } } public static void unlock(String lockKey) { RLock lock = redissonClient.getLock(lockKey); lock.unlock(); } }
public class RedissonTest { public static void main(String[] args) throws Exception{ Thread.sleep(2000L); for (int i = 0; i < 3; i++) { new Thread(() -> { try { //tryLock,第三個(gè)參數(shù)是等待時(shí)間,5秒內(nèi)獲取不到鎖,則直接返回。 第四個(gè)參數(shù) 30是30秒后強(qiáng)制釋放 boolean hasLock = DistributedLock.tryLock("lockKey", TimeUnit.SECONDS,5,30); //獲得分布式鎖 if(hasLock){ System.out.println("idea1: " + Thread.currentThread().getName() + "獲得了鎖"); /** * 由于在DistributedLock.tryLock設(shè)置的等待時(shí)間是5s, * 所以這里如果休眠的小于5秒,這第二個(gè)線程能獲取到鎖, * 如果設(shè)置的大于5秒,則剩下的線程都不能獲取鎖。可以分別試試2s,和8s的情況 */ Thread.sleep(10000L); DistributedLock.unlock("lockKey"); } else { System.out.println("idea1: " + Thread.currentThread().getName() + "無法獲取鎖"); } } catch (Exception e) { e.printStackTrace(); } }) .start(); } } }
我們?cè)俅蜷_一個(gè)idea,可以把代碼復(fù)制一份。同事啟動(dòng)兩個(gè)RedissonTest ,模擬了并發(fā)操作。
測(cè)試結(jié)果:
idea2: Thread-1獲得了鎖
idea2: Thread-0無法獲取鎖
idea2: Thread-2無法獲取鎖
idea1: Thread-2無法獲取鎖
idea1: Thread-0無法獲取鎖
idea1: Thread-1無法獲取鎖
從測(cè)試結(jié)果發(fā)現(xiàn),最后是只能有一個(gè)idea的一個(gè)線程能獲取到鎖。
感謝各位的閱讀,以上就是“如何使用自定義注解實(shí)現(xiàn)redisson分布式鎖”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)如何使用自定義注解實(shí)現(xiàn)redisson分布式鎖這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。