release branch 1.1.0

This commit is contained in:
binbin.hou
2022-12-08 11:15:03 +08:00
parent c45f6b53a0
commit 0bae77fc8a
22 changed files with 692 additions and 138 deletions

View File

@@ -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!");
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}