自定義註解實現分佈式鎖實現
分佈式鎖的實現基於redisson-
背景
很久很久以前,我們的架構都是單體架構,項目也只會部署到一臺服務器,基於JVM的 java 同步工具(如ReentrantLcok或synchronized)完全可以保證我們的業務的 原子性;隨着微服務,分佈式的出現,一個項目會部署到多臺服務器(多個JVM),這時候多個服務之間的一系列操作要保證原子性,基於JVM的 java 同步工具(如ReentrantLcok或synchronized)就無能爲力了,這時候需要一個針對整個項目(包含所有服務)的一個全局鎖來控制業務,這時候分佈式鎖就應運而生。
分佈式鎖的 注意事項
- 加鎖必須設置過期時間(避免死鎖)
- 加鎖操作必須和設置 過期時間 是原子性操作
併發操作下 導致加過期時間失敗問題(某個線程執行完枷鎖操作 未加過期時間 報錯終止) - 過期時間 必須保證業務操作 結束
開始子線程監控 未執行結束 續命(加過期時間) - 必須保證 誰加鎖 誰解鎖
防止高併發下 鎖失效問題
java 源碼
@RestController
public class RedissonLock {
// 分佈式鎖的 注意事項
// 1. 加鎖必須設置過期時間
// (避免死鎖)
// 2. 加鎖操作必須和設置 過期時間 是原子性操作
// 併發操作下 導致加過期時間失敗問題(某個線程執行完枷鎖操作 未加過期時間 報錯終止)
// 3. 過期時間 必須保證業務操作 結束
// 開始子線程監控 未執行結束 續命(加過期時間)
// 4. 必須保證 誰加鎖 誰解鎖
// 防止高併發下 鎖失效問題
static int r = 0;
@Autowired
private RedissonClient redissonClient;
@GetMapping("/testLock")
public int testRedissonLock(@RequestParam boolean isLock) throws InterruptedException {
RLock rLock = null;
int result = 0;
if(isLock){
try{// 獲取鎖
rLock = redissonClient.getLock("test1");
// 上鎖
rLock.lock(12, TimeUnit.SECONDS);
result = dobusiness();
}
finally {
// 解鎖
rLock.unlock();
}
} else {
result = dobusiness();
}
return result;
}
private int dobusiness() throws InterruptedException {
++r;
TimeUnit.SECONDS.sleep(1);
System.out.println(r);
return r;
}
轉自我的 另一篇博客 https://blog.csdn.net/qq_41692766/article/details/105770758
使用自定義註解方式實現分佈式鎖控制
主要使用技術:
- 自定義註解
- 切面編程
1. 自定義註解的使用
請參考 我的另一篇博客:https://blog.csdn.net/qq_41692766/article/details/105821144(此處不贅述)
2. 面向切面編程
請參考 我的另一篇博客:https://blog.csdn.net/qq_41692766/article/details/105821218(此處不贅述)
進入正題
準備工作完成,我們直奔主題:
-
redisson 服務接口
package com.beauty.beautybase.service; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * description Redisson 服務類 * * @author yufw * date 2020/4/27 16:40 */ public interface RedissonService { /** * 無指定時間 加鎖 */ void lock(String name); /** * 指定時間 加鎖 * * @param leaseTime * @param unit */ void lock(String name, long leaseTime, TimeUnit unit); boolean tryLock(String name); boolean tryLock(String name, long time, TimeUnit unit) throws InterruptedException; boolean isLocked(String name); void unlock(String name); }
-
接口實現
package com.beauty.beautybase.service.Impl; import com.beauty.beautybase.service.RedissonService; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * description * * @author yufw * date 2020/4/27 16:43 */ @Service public class RedissonServiceImpl implements RedissonService { @Autowired private RedissonClient redissonClient; private RLock getLock(String name) { RLock lock = redissonClient.getLock(name); return lock; } /** * 無指定時間 加鎖 */ @Override public void lock(String name) { getLock(name).lock(); } /** * 指定時間 加鎖 * * @param leaseTime * @param unit */ @Override public void lock(String name, long leaseTime, TimeUnit unit) { } @Override public boolean tryLock(String name) { return false; } @Override public boolean tryLock(String name, long time, TimeUnit unit) throws InterruptedException { return false; } @Override public boolean isLocked(String name) { return false; } @Override public void unlock(String name) { getLock(name).unlock(); } }
-
自定義註解
package com.beauty.beautybase.annotion; import java.lang.annotation.*; import java.util.concurrent.TimeUnit; @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DistributeLock { /** * 鎖類型 * * @return */ LockType type() default LockType.LOCK; /** * 分佈式鎖 名稱 * * @return */ String name() default "lock"; long leaseTime() default -1; TimeUnit unit() default TimeUnit.SECONDS; }
-
註解邏輯
package com.beauty.beautybase.AOP; import com.beauty.beautybase.annotion.DistributeLock; import com.beauty.beautybase.annotion.LockType; import com.beauty.beautybase.service.RedissonService; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * description 分佈式鎖自定義註解 切面 * * @author yufw * date 2020/4/27 13:11 */ @Aspect @Component public class DistributeLockAop { @Autowired RedissonService redissonService; /** * 切入點 */ @Pointcut("@annotation(com.beauty.beautybase.annotion.DistributeLock)") public void doBusiness() { } /** * 前事件 * * @param joinPoint */ @Before("doBusiness()") public void doBefore(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //獲取執行方法 Method method = signature.getMethod(); // 獲取註解信息 DistributeLock distributeLock = method.getAnnotation(DistributeLock.class); if (null != distributeLock) { //獲取註解參數值 String lockName = distributeLock.name(); LockType type = distributeLock.type(); if (type == LockType.LOCK) { redissonService.lock(lockName); System.out.println("加鎖成功"); } } } /** * 後事件 * * @param joinPoint */ @After("doBusiness()") public void doAfter(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //獲取執行方法 Method method = signature.getMethod(); // 獲取註解信息 DistributeLock distributeLock = method.getAnnotation(DistributeLock.class); //獲取執行方法名 String methodName = method.getName(); //獲取方法傳遞的參數 Object[] args = joinPoint.getArgs(); if (null != distributeLock) { //獲取註解參數值 String lockName = distributeLock.name(); if (null != distributeLock) { redissonService.unlock(lockName); System.out.println("解鎖成功"); } } } }
-
測試接口編寫
package com.beauty.beautybase.controller; import com.beauty.beautybase.annotion.DistributeLock; import com.beauty.beautybase.annotion.LockType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; /** * description * * @author yufw * date 2020/4/28 9:42 */ @RestController @RequestMapping("/commonBase") public class DistributeLockController { @DistributeLock(type = LockType.LOCK, name = "lock") @GetMapping("/lock") public void testLock() throws Exception { System.out.println("test_lock"); System.out.println("需要加分佈式鎖的業務邏輯"); // 此處測試 如果處理 業務邏輯 報錯 是否會 解鎖(防止死鎖) //throw new Exception("業務報錯"); } @GetMapping("/lockTimed") public void testLockTimed() { System.out.println("test_lockTimed"); } @GetMapping("/tryLock") public void testTryLock() { } @GetMapping("tryLockTimed") public void testTryLockTimed(@RequestParam int time, @RequestParam TimeUnit unit) { } }
-
執行get請求:http://localhost:60030/commonBase/lock
**備註:**此功能會持續優化,暫簡單實現
源碼地址:https://gitee.com/twelfthLunarMonthFourteen/pub_beauty/tree/hotfix/beauty-base/src/main/java/com/beauty/beautybase
個人水平有限,如有問題,請各路大神指教留言,評論區討論,虛心接納
如果覺得有幫助,請點贊收藏,謝謝