lock-spring-boot-starter
分布式锁 starter
介绍
说明
工程接口(扩展点):
接口->com.javacoo.lock.client.api.Lock
基于xkernel 提供的SPI机制,结合SpringBoot注解 ConditionalOnBean,ConditionalOnProperty实现。
类关系图
项目结构
lock-spring-boot-starter
└── src
├── main
│ ├── java
│ │ └── com.javacoo
│ │ ├────── lock
│ │ │ ├──────client
│ │ │ │ ├── api
│ │ │ │ │ ├── annotation
│ │ │ │ │ │ └── MethodLock 锁注解
│ │ │ │ │ ├── client
│ │ │ │ │ │ └── Lock 锁接口
│ │ │ │ │ ├── aspect
│ │ │ │ │ │ └── LockAspect 锁切面
│ │ │ │ │ ├── config
│ │ │ │ │ │ └── LockConfig 锁配置
│ │ │ │ │ ├── exception
│ │ │ │ │ └── LockException 锁异常
│ │ │ │ └── internal 接口内部实现
│ │ │ │ ├── redis
│ │ │ │ ├── RedissionConfig Redission配置类
│ │ │ │ └── RedssionLock 锁接口实现类
│ │ │ └──────starter
│ │ │ ├── LockAutoConfiguration 自动配置类
│ │ │ └── LockHolder 锁接口对象持有者
│ └── resource
│ ├── META-INF
│ └── ext
│ └── internal
│ └── com.javacoo.lock.client.api.Lock
└── test 测试
如何使用
-
pom依赖:
<dependency> <groupId>com.javacoo</groupId> <artifactId>lock-spring-boot-starter</artifactId> <version>1.0.0</version> </dependency>
-
配置参数,如果使用默认实现,则无需配置,如要扩展则需要,配置如下:
#lock是否可用,默认可用 lock.enabled = true #lock实现,默认内部实现 lock.impl = default
-
方法加注解,如:
@MethodLock(fieldName = "applNo") @Override public BaseResponse gjjloanConfirm(LoanConfirmRequest request)
SPI扩展
基于xkernel 提供的SPI机制,扩展非常方便,大致步骤如下:
-
实现锁接口:如 com.xxxx.xxxx.MyLockImpl
-
配置锁接口:
-
在项目resource目录新建包->META-INF->services
-
创建com.javacoo.lock.client.api.Lock文件,文件内容:实现类的全局限定名,如:
myLock=com.xxxx.xxxx.MyLockImpl
-
修改配置文件,添加如下内容:
#lock实现 lock.impl = myLock
-
默认实现
1、锁接口:
/**
* 锁接口
* <li></li>
*
* @author: duanyong
* @since: 2020/6/22 10:19
*/
@Spi(LockConfig.DEFAULT_IMPL)
public interface Lock<T> {
/**超时时间*/
int TIMEOUT_SECOND = 60;
/**
* 对lockKey加锁
* <li></li>
* @author duanyong
* @date 2020/6/22 10:30
* @param lockKey:lockKey
* @return: T 锁对象
*/
T lock(String lockKey);
/**
* 对lockKey加锁,timeout后过期
* <li></li>
* @author duanyong
* @date 2020/6/22 10:31
* @param lockKey: lockKey
* @param timeout: 锁超时时间,单位:秒
* @return: T 锁对象
*/
T lock(String lockKey, int timeout);
/**
* 对lockKey加锁,指定时间单位,timeout后过期
* <li></li>
* @author duanyong
* @date 2020/6/22 10:33
* @param lockKey: lockKey
* @param unit: 时间单位
* @param timeout: 锁超时时间
* @return: T 锁对象
*/
T lock(String lockKey, TimeUnit unit , int timeout);
/**
* 尝试获取锁
* <li></li>
* @author duanyong
* @date 2020/6/22 10:35
* @param lockKey: lockKey
* @return: boolean 是否成功,成功返回:true
*/
boolean tryLock(String lockKey);
/**
* 尝试获取锁
* <li></li>
* @author duanyong
* @date 2020/6/22 10:35
* @param lockKey: lockKey
* @param waitTime:最多等待时间
* @param timeout:上锁后自动释放锁时间
* @return: boolean 是否成功,成功返回:true
*/
boolean tryLock(String lockKey, int waitTime, int timeout);
/**
* 尝试获取锁
* <li></li>
* @author duanyong
* @date 2020/6/22 10:36
* @param lockKey: lockKey
* @param unit:时间单位
* @param waitTime:最多等待时间
* @param timeout:上锁后自动释放锁时间
* @return: boolean 是否成功,成功返回:true
*/
boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int timeout);
/**
* 释放锁
* <li></li>
* @author duanyong
* @date 2020/6/22 10:37
* @param lockKey: lockKey
* @return: void
*/
void unlock(String lockKey);
/**
* 释放锁
* <li></li>
* @author duanyong
* @date 2020/6/22 10:37
* @param lock:锁对象
* @return: void
*/
void unlock(T lock);
}
2、实现锁接口,如默认实现:
/**
* 锁接口实现类
* <li>基于Redssion</li>
*
* @author: duanyong
* @since: 2020/6/22 10:39
*/
@Slf4j
public class RedssionLock implements Lock<RLock> {
/**约定缓存前缀:appId:模块:key*/
public static final String CACHE_PREFIX_KEY ="javacoo:service:lock:";
@Autowired
private RedissonClient redissonClient;
/**
* 对lockKey加锁
* <li>阻塞获取锁</li>
*
* @param lockKey :lockKey
* @author duanyong
* @date 2020/6/22 10:30
* @return: T 锁对象
*/
@Override
public RLock lock(String lockKey) {
log.info(">>>>> lock key[{}]",lockKey);
Assert.hasText(lockKey,"lockKey 不能为空");
RLock lock = redissonClient.getLock(CACHE_PREFIX_KEY +lockKey);
lock.lock();
return lock;
}
/**
* 对lockKey加锁,timeout后过期
* <li></li>
*
* @param lockKey : lockKey
* @param timeout : 锁超时时间,单位:秒
* @author duanyong
* @date 2020/6/22 10:31
* @return: T 锁对象
*/
@Override
public RLock lock(String lockKey, int timeout) {
return lock(lockKey, TimeUnit.SECONDS,timeout);
}
/**
* 对lockKey加锁,指定时间单位,timeout后过期
* <li></li>
*
* @param lockKey : lockKey
* @param unit : 时间单位
* @param timeout : 锁超时时间
* @author duanyong
* @date 2020/6/22 10:33
* @return: T 锁对象
*/
@Override
public RLock lock(String lockKey, TimeUnit unit, int timeout) {
log.info(">>>>> lockKey:{},TimeUnit:{},timeout:{}",lockKey,unit,timeout);
Assert.hasText(lockKey,"lockKey 不能为空");
RLock lock = redissonClient.getLock(CACHE_PREFIX_KEY +lockKey);
lock.lock(timeout, unit);
return lock;
}
/**
* 尝试获取锁
* <li>获取锁失败立即返回,上锁后60秒自动释放锁</li>
*
* @param lockKey : lockKey
* @author duanyong
* @date 2020/6/22 10:35
* @return: boolean 是否成功,成功返回:true
*/
@Override
public boolean tryLock(String lockKey) {
return tryLock(lockKey,0,60);
}
/**
* 尝试获取锁
* <li></li>
*
* @param lockKey : lockKey
* @param waitTime :最多等待时间
* @param timeout :上锁后自动释放锁时间
* @author duanyong
* @date 2020/6/22 10:35
* @return: boolean 是否成功,成功返回:true
*/
@Override
public boolean tryLock(String lockKey, int waitTime, int timeout) {
return tryLock(lockKey, TimeUnit.SECONDS,waitTime,timeout);
}
/**
* 尝试获取锁
* <li></li>
*
* @param lockKey : lockKey
* @param unit :时间单位
* @param waitTime :最多等待时间
* @param timeout :上锁后自动释放锁时间
* @author duanyong
* @date 2020/6/22 10:36
* @return: boolean 是否成功,成功返回:true
*/
@Override
public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int timeout) {
Assert.hasText(lockKey,"lockKey 不能为空");
lockKey = CACHE_PREFIX_KEY +lockKey;
log.info(">>>>> tryLock lockKey:{},TimeUnit:{},waitTime:{},timeout:{}",lockKey,unit,waitTime,timeout);
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, timeout, unit);
} catch (Exception e) {
e.printStackTrace();
log.error("尝试获取锁:{},TimeUnit:{},waitTime:{},timeout:{},失败",lockKey,unit