一、簡介
Lock4j
是一個分散式鎖元件,它提供了多種不同的支援以滿足不同效能和環境的需求,基於Spring AOP
的宣告式和程式設計式分散式鎖,支援RedisTemplate、Redisson、Zookeeper
。
二、特性
簡單易用,功能強大,擴充套件性強。
支援
redission, redisTemplate, zookeeper
,可混用,支援擴充套件。
Gitee:gitee.com/baomidou/lo…
三、使用前準備
3.1 引入依賴
<!-- Lock4j --> <!-- 若使用redisTemplate作為分散式鎖底層,則需要引入 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>lock4j-redis-template-spring-boot-starter</artifactId> <version>2.2.4</version> </dependency> <!-- 若使用redisson作為分散式鎖底層,則需要引入 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>lock4j-redisson-spring-boot-starter</artifactId> <version>2.2.4</version> </dependency>
3.2 新增redis配置
spring: redis: database: 0 # Redis伺服器地址 寫你的ip host: 127.0.0.1 # Redis伺服器連線埠 port: 6379 # Redis伺服器連線密碼(預設為空) password: # 連線池最大連線數(使用負值表示沒有限制 類似於mysql的連線池 jedis: pool: max-active: 200 # 連線池最大阻塞等待時間(使用負值表示沒有限制) 表示連線池的連結拿完了 現在去申請需要等待的時間 max-wait: -1 # 連線池中的最大空閒連線 max-idle: 10 # 連線池中的最小空閒連線 min-idle: 0 # 連線超時時間(毫秒) 去連結redis服務端 timeout: 6000
四、註解屬性介紹
package com.baomidou.lock.annotation; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Lock4j { String name() default ""; Class<? extends LockExecutor> executor() default LockExecutor.class; String[] keys() default {""}; long expire() default -1L; long acquireTimeout() default -1L; boolean autoRelease() default true; }
@Lock4j註解屬性 | 說明 |
---|---|
name | 需要鎖住的key 名稱 |
executor | 可以透過該引數設定自定義特定的執行器 |
keys | 需要鎖住的keys 名稱,可以是多個 |
expire | 鎖過期時間,主要是用來防止死鎖 |
acquireTimeout | 可以理解為排隊等待時長,超過這個時長就退出排隊,並排除獲取鎖超時異常 |
autoRelease | 是否自動釋放鎖,預設是true |
五、簡單使用
@RestController @RequestMapping("/mock") public class MockController { @GetMapping("/lockMethod") @Lock4j(keys = {"#key"}, acquireTimeout = 1000, expire = 10000) public Result lockMethod(@RequestParam String key) { ThreadUtil.sleep(5000); return Result.OK(key); } }
開啟瀏覽器視窗,重複重新整理訪問:http://localhost:8080/mock/lockMethod?key=123
成功獲得鎖訪問結果:
{ "success": true, "message": "操作成功!", "code": 200, "result": "123", "timestamp": 1678866083211 }
搶佔不到鎖,Lock4j
會丟擲com.baomidou.lock.exception.LockFailureException: request failed,please retry it.
異常,透過全域性異常處理返回如下結果:
{ "success": false, "message": "操作失敗,request failed,please retry it.", "code": 500, "result": null, "timestamp": 1678866034929 }
六、高階使用
6.1 自定義執行器Exector
/** * 自定義分散式鎖執行器 * * @author: austin * @since: 2023/3/15 15:45 */ @Component public class CustomRedissonLockExecutor extends AbstractLockExecutor { @Override public Object acquire(String lockKey, String lockValue, long expire, long acquireTimeout) { return null; } @Override public boolean releaseLock(String key, String value, Object lockInstance) { return false; } }
在註解上直接指定特定的執行器:@Lock4j(executor = CustomRedissonLockExecutor.class)
。
6.2 自定義分散式鎖key生成器
/** * 自定義分散式鎖key生成器 * * @author: austin * @since: 2023/3/15 15:46 */ @Component public class CustomKeyBuilder extends DefaultLockKeyBuilder { public CustomKeyBuilder(BeanFactory beanFactory) { super(beanFactory); } }
6.3 自定義搶佔鎖失敗執行策略
/** * 自定義搶佔鎖失敗執行策略 * * @author: austin * @since: 2023/3/15 15:49 */ @Component public class GrabLockFailureStrategy implements LockFailureStrategy { @Override public void onLockFailure(String key, Method method, Object[] arguments) { } }
預設的鎖獲取失敗策略為 com.baomidou.lock.DefaultLockFailureStrategy.
6.4 手動加鎖釋放鎖
@Service public class LockServiceImpl implements LockService { @Autowired private LockTemplate lockTemplate; @Override public void lock(String resourceKey) { LockInfo lock = lockTemplate.lock(resourceKey, 10000L, 2000L, CustomRedissonLockExecutor.class); if (lock == null) { // 獲取不到鎖 throw new FrameworkException("業務處理中,請稍後再試..."); } // 獲取鎖成功,處理業務 try { doBusiness(); } catch (Exception e) { throw new RuntimeException(e); } finally { lockTemplate.releaseLock(lock); } } private void doBusiness() { // TODO 業務執行邏輯 } }