release branch 1.1.0
This commit is contained in:
@@ -4,10 +4,9 @@ import com.github.houbb.common.cache.api.service.ICommonCacheService;
|
||||
import com.github.houbb.heaven.util.common.ArgUtil;
|
||||
import com.github.houbb.id.api.Id;
|
||||
import com.github.houbb.id.core.core.Ids;
|
||||
import com.github.houbb.lock.api.core.ILock;
|
||||
import com.github.houbb.lock.api.core.ILockSupport;
|
||||
import com.github.houbb.lock.api.core.ILockSupportContext;
|
||||
import com.github.houbb.lock.core.constant.LockConst;
|
||||
import com.github.houbb.lock.api.core.*;
|
||||
import com.github.houbb.lock.core.support.format.LockKeyFormat;
|
||||
import com.github.houbb.lock.core.support.handler.LockReleaseFailHandler;
|
||||
import com.github.houbb.lock.core.support.lock.LockSupportContext;
|
||||
import com.github.houbb.lock.core.support.lock.RedisLockSupport;
|
||||
import com.github.houbb.redis.config.core.factory.JedisRedisServiceFactory;
|
||||
@@ -20,48 +19,49 @@ import java.util.concurrent.TimeUnit;
|
||||
* @author binbin.hou
|
||||
* @since 0.0.4
|
||||
*/
|
||||
public final class LockBs implements ILock{
|
||||
public final class LockBs implements ILock {
|
||||
|
||||
private LockBs(){}
|
||||
private LockBs() {
|
||||
}
|
||||
|
||||
public static LockBs newInstance() {
|
||||
return new LockBs();
|
||||
}
|
||||
|
||||
/**
|
||||
* 加锁锁定时间
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private int lockExpireMills = LockConst.DEFAULT_EXPIRE_MILLS;
|
||||
|
||||
/**
|
||||
* 标识策略
|
||||
*
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private Id id = Ids.uuid32();
|
||||
|
||||
/**
|
||||
* 缓存策略
|
||||
*
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private ICommonCacheService cache = JedisRedisServiceFactory.pooled("127.0.0.1", 6379);
|
||||
|
||||
/**
|
||||
* 锁支持策略
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private ILockSupport lockSupport = new RedisLockSupport();
|
||||
|
||||
/**
|
||||
* 锁上下文
|
||||
* @since 1.0.0
|
||||
* 锁 key 格式化
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private ILockSupportContext lockSupportContext = null;
|
||||
private ILockKeyFormat lockKeyFormat = new LockKeyFormat();
|
||||
|
||||
public LockBs lockExpireMills(int lockExpireMills) {
|
||||
this.lockExpireMills = lockExpireMills;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 锁释放失败处理类
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private ILockReleaseFailHandler lockReleaseFailHandler = new LockReleaseFailHandler();
|
||||
|
||||
public LockBs id(Id id) {
|
||||
ArgUtil.notNull(id, "id");
|
||||
@@ -84,48 +84,67 @@ public final class LockBs implements ILock{
|
||||
return this;
|
||||
}
|
||||
|
||||
public LockBs lockKeyFormat(ILockKeyFormat lockKeyFormat) {
|
||||
ArgUtil.notNull(lockKeyFormat, "lockKeyFormat");
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public LockBs init() {
|
||||
this.lockSupportContext = LockSupportContext.newInstance()
|
||||
.id(id)
|
||||
.cache(cache)
|
||||
.lockExpireMills(lockExpireMills);
|
||||
|
||||
this.lockKeyFormat = lockKeyFormat;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LockBs lockReleaseFailHandler(ILockReleaseFailHandler lockReleaseFailHandler) {
|
||||
ArgUtil.notNull(lockReleaseFailHandler, "lockReleaseFailHandler");
|
||||
|
||||
this.lockReleaseFailHandler = lockReleaseFailHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ILockReleaseFailHandler lockReleaseFailHandler() {
|
||||
return lockReleaseFailHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(long time, TimeUnit unit, String key) {
|
||||
ArgUtil.notEmpty(key, "key");
|
||||
this.checkInitStatus();
|
||||
public boolean tryLock(String key, TimeUnit timeUnit, long lockTime, long waitLockTime) {
|
||||
ILockSupportContext supportContext = buildLockSupportContext(key, timeUnit, lockTime, waitLockTime);
|
||||
return this.lockSupport.tryLock(supportContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key, TimeUnit timeUnit, long lockTime) {
|
||||
return this.tryLock(key, timeUnit, lockTime, 0);
|
||||
}
|
||||
|
||||
return this.lockSupport.tryLock(time, unit, key, lockSupportContext);
|
||||
@Override
|
||||
public boolean tryLock(String key, long lockTime) {
|
||||
return this.tryLock(key, TimeUnit.SECONDS, lockTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key) {
|
||||
ArgUtil.notEmpty(key, "key");
|
||||
this.checkInitStatus();
|
||||
|
||||
return this.lockSupport.tryLock(key, lockSupportContext);
|
||||
return this.tryLock(key, 60);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unlock(String key) {
|
||||
ILockSupportContext supportContext = buildLockSupportContext(key, TimeUnit.SECONDS, 0, 0);
|
||||
return this.lockSupport.unlock(supportContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建上下文
|
||||
*
|
||||
* @param key key
|
||||
* @param timeUnit 时间
|
||||
* @param lockTime 加锁时间
|
||||
* @param waitLockTime 等待加锁时间
|
||||
* @return 结果
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private ILockSupportContext buildLockSupportContext(String key, TimeUnit timeUnit, long lockTime, long waitLockTime) {
|
||||
ArgUtil.notEmpty(key, "key");
|
||||
this.checkInitStatus();
|
||||
ArgUtil.notNull(timeUnit, "timeUnit");
|
||||
|
||||
return this.lockSupport.unlock(key, lockSupportContext);
|
||||
ILockSupportContext context = LockSupportContext.newInstance().id(id).cache(cache).lockKeyFormat(lockKeyFormat).lockReleaseFailHandler(lockReleaseFailHandler).key(key).timeUnit(timeUnit).lockTime(lockTime).waitLockTime(waitLockTime);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
private void checkInitStatus() {
|
||||
ArgUtil.notNull(lockSupportContext, "please init() first!");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.github.houbb.lock.core.support.format;
|
||||
|
||||
import com.github.houbb.lock.api.core.ILockKeyFormat;
|
||||
import com.github.houbb.lock.api.core.ILockKeyFormatContext;
|
||||
|
||||
/**
|
||||
* 简单的格式化处理
|
||||
* @since 1.2.0
|
||||
* @author dh
|
||||
*/
|
||||
public class LockKeyFormat implements ILockKeyFormat {
|
||||
|
||||
@Override
|
||||
public String format(ILockKeyFormatContext formatContext) {
|
||||
String rawKey = formatContext.rawKey();
|
||||
|
||||
String format = "DISTRIBUTED-LOCK:%s";
|
||||
return String.format(format, rawKey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.github.houbb.lock.core.support.format;
|
||||
|
||||
import com.github.houbb.lock.api.core.ILockKeyFormatContext;
|
||||
|
||||
/**
|
||||
* 上下文
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class LockKeyFormatContext implements ILockKeyFormatContext {
|
||||
|
||||
|
||||
/**
|
||||
* 原始的 key
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private String rawKey;
|
||||
|
||||
public static LockKeyFormatContext newInstance() {
|
||||
return new LockKeyFormatContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String rawKey() {
|
||||
return rawKey;
|
||||
}
|
||||
|
||||
public LockKeyFormatContext rawKey(String rawKey) {
|
||||
this.rawKey = rawKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.github.houbb.lock.core.support.handler;
|
||||
|
||||
import com.github.houbb.lock.api.core.ILockReleaseFailHandler;
|
||||
import com.github.houbb.lock.api.core.ILockReleaseFailHandlerContext;
|
||||
import com.github.houbb.log.integration.core.Log;
|
||||
import com.github.houbb.log.integration.core.LogFactory;
|
||||
|
||||
/**
|
||||
* 释放锁失败处理类
|
||||
*
|
||||
* @author binbin.hou
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class LockReleaseFailHandler implements ILockReleaseFailHandler {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(LockReleaseFailHandler.class);
|
||||
|
||||
@Override
|
||||
public void handle(ILockReleaseFailHandlerContext context) {
|
||||
LOG.error("[LOCK] release lock failed {}", context.key());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.github.houbb.lock.core.support.handler;
|
||||
|
||||
import com.github.houbb.lock.api.core.ILockReleaseFailHandlerContext;
|
||||
|
||||
/**
|
||||
* 锁释放失败上下文
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class LockReleaseFailHandlerContext implements ILockReleaseFailHandlerContext {
|
||||
|
||||
/**
|
||||
* 释放锁对应的 key
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private String key;
|
||||
|
||||
public static LockReleaseFailHandlerContext newInstance() {
|
||||
return new LockReleaseFailHandlerContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public LockReleaseFailHandlerContext key(String key) {
|
||||
this.key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,13 @@ package com.github.houbb.lock.core.support.lock;
|
||||
|
||||
import com.github.houbb.common.cache.api.service.ICommonCacheService;
|
||||
import com.github.houbb.id.api.Id;
|
||||
import com.github.houbb.lock.api.core.ILockKeyFormat;
|
||||
import com.github.houbb.lock.api.core.ILockReleaseFailHandler;
|
||||
import com.github.houbb.lock.api.core.ILockSupportContext;
|
||||
import com.github.houbb.lock.core.support.format.LockKeyFormat;
|
||||
import com.github.houbb.lock.core.support.handler.LockReleaseFailHandler;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 分布式锁接口定义
|
||||
@@ -25,13 +31,43 @@ public class LockSupportContext implements ILockSupportContext {
|
||||
* 缓存策略
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private ICommonCacheService commonCacheService;
|
||||
private ICommonCacheService cache;
|
||||
|
||||
/**
|
||||
* 锁的过期时间
|
||||
* @since 1.0.0
|
||||
* 时间单位
|
||||
*/
|
||||
private int lockExpireMills;
|
||||
private TimeUnit timeUnit;
|
||||
|
||||
/**
|
||||
* 加锁时间
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private long lockTime;
|
||||
|
||||
/**
|
||||
* 等待加锁时间
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private long waitLockTime;
|
||||
|
||||
/**
|
||||
* 缓存对应的 key
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* 锁 key 格式化
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private ILockKeyFormat lockKeyFormat;
|
||||
|
||||
/**
|
||||
* 锁释放失败处理类
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private ILockReleaseFailHandler lockReleaseFailHandler;
|
||||
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
@@ -45,21 +81,72 @@ public class LockSupportContext implements ILockSupportContext {
|
||||
|
||||
@Override
|
||||
public ICommonCacheService cache() {
|
||||
return commonCacheService;
|
||||
return cache;
|
||||
}
|
||||
|
||||
public LockSupportContext cache(ICommonCacheService commonCacheService) {
|
||||
this.commonCacheService = commonCacheService;
|
||||
public LockSupportContext cache(ICommonCacheService cache) {
|
||||
this.cache = cache;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lockExpireMills() {
|
||||
return lockExpireMills;
|
||||
public TimeUnit timeUnit() {
|
||||
return timeUnit;
|
||||
}
|
||||
|
||||
public LockSupportContext lockExpireMills(int lockExpireMills) {
|
||||
this.lockExpireMills = lockExpireMills;
|
||||
public LockSupportContext timeUnit(TimeUnit timeUnit) {
|
||||
this.timeUnit = timeUnit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long lockTime() {
|
||||
return lockTime;
|
||||
}
|
||||
|
||||
public LockSupportContext lockTime(long lockTime) {
|
||||
this.lockTime = lockTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long waitLockTime() {
|
||||
return waitLockTime;
|
||||
}
|
||||
|
||||
public LockSupportContext waitLockTime(long waitLockTime) {
|
||||
this.waitLockTime = waitLockTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public LockSupportContext key(String key) {
|
||||
this.key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILockKeyFormat lockKeyFormat() {
|
||||
return lockKeyFormat;
|
||||
}
|
||||
|
||||
public LockSupportContext lockKeyFormat(ILockKeyFormat lockKeyFormat) {
|
||||
this.lockKeyFormat = lockKeyFormat;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILockReleaseFailHandler lockReleaseFailHandler() {
|
||||
return lockReleaseFailHandler;
|
||||
}
|
||||
|
||||
public LockSupportContext lockReleaseFailHandler(ILockReleaseFailHandler lockReleaseFailHandler) {
|
||||
this.lockReleaseFailHandler = lockReleaseFailHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.github.houbb.lock.core.support.lock;
|
||||
|
||||
import com.github.houbb.common.cache.api.service.ICommonCacheService;
|
||||
import com.github.houbb.heaven.util.lang.StringUtil;
|
||||
import com.github.houbb.id.api.Id;
|
||||
import com.github.houbb.id.core.util.IdThreadLocalHelper;
|
||||
import com.github.houbb.lock.api.core.ILockKeyFormat;
|
||||
import com.github.houbb.lock.api.core.ILockSupport;
|
||||
import com.github.houbb.lock.api.core.ILockSupportContext;
|
||||
import com.github.houbb.lock.core.support.format.LockKeyFormatContext;
|
||||
import com.github.houbb.log.integration.core.Log;
|
||||
import com.github.houbb.log.integration.core.LogFactory;
|
||||
import com.github.houbb.redis.config.core.constant.JedisConst;
|
||||
@@ -22,25 +25,27 @@ public class RedisLockSupport implements ILockSupport {
|
||||
private final Log log = LogFactory.getLog(RedisLockSupport.class);
|
||||
|
||||
@Override
|
||||
public boolean tryLock(long time, TimeUnit unit, String key, ILockSupportContext context) {
|
||||
public boolean tryLock(ILockSupportContext context) {
|
||||
long startTimeMills = System.currentTimeMillis();
|
||||
|
||||
// 一次获取,直接成功
|
||||
boolean result = this.tryLock(key, context);
|
||||
boolean result = this.doLock(context);
|
||||
if(result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 时间判断
|
||||
if(time <= 0) {
|
||||
final TimeUnit timeUnit = context.timeUnit();
|
||||
final long waitLockTime = context.waitLockTime();
|
||||
if(waitLockTime <= 0) {
|
||||
return false;
|
||||
}
|
||||
long durationMills = unit.toMillis(time);
|
||||
long durationMills = timeUnit.toMillis(waitLockTime);
|
||||
long endMills = startTimeMills + durationMills;
|
||||
|
||||
// 循环等待
|
||||
while (System.currentTimeMillis() < endMills) {
|
||||
result = tryLock(key, context);
|
||||
result = this.doLock(context);
|
||||
if(result) {
|
||||
return true;
|
||||
}
|
||||
@@ -49,33 +54,48 @@ public class RedisLockSupport implements ILockSupport {
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
log.debug("[LOCK] try lock wait 1 mills.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key, ILockSupportContext context) {
|
||||
/**
|
||||
* 执行加锁
|
||||
* @param context 上下文
|
||||
* @return 结果
|
||||
*/
|
||||
protected boolean doLock(ILockSupportContext context) {
|
||||
final String key = this.getActualKey(context);
|
||||
|
||||
// 生成当前线程的唯一标识
|
||||
Id id = context.id();
|
||||
final Id id = context.id();
|
||||
final String requestId = id.id();
|
||||
IdThreadLocalHelper.put(requestId);
|
||||
log.info("[LOCK] BEGIN TRY LOCK key: {} requestId: {}", key, requestId);
|
||||
|
||||
final ICommonCacheService commonCacheService = context.cache();
|
||||
final int lockExpireMills = context.lockExpireMills();
|
||||
final TimeUnit timeUnit = context.timeUnit();
|
||||
final long lockTime = context.lockTime();
|
||||
final int lockExpireMills = (int) timeUnit.toMillis(lockTime);
|
||||
|
||||
String result = commonCacheService.set(key, requestId, JedisConst.SET_IF_NOT_EXIST, JedisConst.SET_WITH_EXPIRE_TIME, lockExpireMills);
|
||||
log.info("[LOCK] END TRY LOCK key: {}, requestId: {}, result: {}", key, requestId, result);
|
||||
log.info("[LOCK] END TRY LOCK key: {}, requestId: {}, lockExpireMills: {}, result: {}", key, requestId, lockExpireMills, result);
|
||||
return JedisConst.OK.equalsIgnoreCase(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unlock(String key, ILockSupportContext context) {
|
||||
public boolean unlock(ILockSupportContext context) {
|
||||
final String key = this.getActualKey(context);
|
||||
|
||||
String requestId = IdThreadLocalHelper.get();
|
||||
log.info("[LOCK] BEGIN UN LOCK key: {} requestId: {}", key, requestId);
|
||||
|
||||
if(StringUtil.isEmpty(requestId)) {
|
||||
log.warn("[LOCK] UNLOCK requestId not found, ignore");
|
||||
return false;
|
||||
}
|
||||
|
||||
final ICommonCacheService commonCacheService = context.cache();
|
||||
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||
Object result = commonCacheService.eval(script, Collections.singletonList(key), Collections.singletonList(requestId));
|
||||
@@ -83,4 +103,21 @@ public class RedisLockSupport implements ILockSupport {
|
||||
return JedisConst.RELEASE_SUCCESS.equals(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建真正的 key
|
||||
* @param context 上下文
|
||||
* @return 结果
|
||||
* @since 1.2.0
|
||||
*/
|
||||
private String getActualKey(ILockSupportContext context) {
|
||||
final String rawKey = context.key();
|
||||
final ILockKeyFormat keyFormat = context.lockKeyFormat();
|
||||
LockKeyFormatContext formatContext = LockKeyFormatContext.newInstance()
|
||||
.rawKey(rawKey);
|
||||
|
||||
String key = keyFormat.format(formatContext);
|
||||
log.info("[LOCK] format rawKey: {} to key: {}", rawKey, key);
|
||||
return key;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user