19 Commits

Author SHA1 Message Date
binbin.hou
c45f6b53a0 release branch 1.1.0 2022-12-07 21:00:45 +08:00
binbin.hou
27a931ae77 [Feature] add for new 2022-12-07 18:39:00 +08:00
binbin.hou
8bf1df19c2 [Feature] add for new 2022-12-07 16:54:37 +08:00
binbin.hou
c0e3cc4bf2 release branch 1.0.0 2022-12-07 16:43:21 +08:00
binbin.hou
402653393d release branch 0.0.4 2022-12-07 16:40:24 +08:00
binbin.hou
7fd29cd1f2 release branch 0.0.4 2022-04-17 19:16:44 +08:00
binbin.hou
ecd879763a release branch 0.0.3 2021-12-08 10:19:58 +08:00
binbin.hou
d06effa306 [Feature] add for new 2020-11-08 13:07:13 +08:00
houbb
bce83c6d1e [Feature] add for new 2020-10-31 12:53:31 +08:00
houbb
2016605dfd Merge remote-tracking branch 'origin/master' 2020-10-30 23:45:49 +08:00
houbb
d273441a72 [Feature] add for new 2020-10-30 23:45:03 +08:00
binbin.hou
2cc9eccdee [Feature] add for new 2020-10-24 20:21:11 +08:00
binbin.hou
4beac5f889 [Feature] add for new 2020-10-20 13:21:17 +08:00
binbin.hou
629c6b8fce release branch 0.0.2 2020-10-20 12:44:35 +08:00
houbb
56e25d67e3 [Feature] add for new 2020-10-19 23:38:19 +08:00
binbin.hou
67f8b1e2a7 [Feature] add for new 2020-10-19 18:23:20 +08:00
houbb
acbd8f4022 [Feature] add for new 2020-10-17 15:38:19 +08:00
binbin.hou
422ec999ac [Feature] add for new 2020-09-10 16:20:38 +08:00
binbin.hou
71d554ba3b [Feature] add for new 2020-09-10 14:13:29 +08:00
56 changed files with 1499 additions and 483 deletions

View File

@@ -13,4 +13,35 @@
| 序号 | 变更类型 | 说明 | 时间 | 备注 |
|:---|:---|:---|:---|:--|
| 1 | A | 基本 api 定义 | 2020-9-2 14:45:40 | |
| 1 | A | 基本 api 定义 | 2020-9-2 14:45:40 | |
# release_0.0.2
| 序号 | 变更类型 | 说明 | 时间 | 备注 |
|:---|:---|:---|:---|:--|
| 1 | A | 常见锁添加 | 2020-9-2 14:45:40 | |
# release_0.0.3
| 序号 | 变更类型 | 说明 | 时间 | 备注 |
|:---|:---|:---|:---|:--|
| 1 | A | redis 锁独立,便于使用 | 2021-12-08 14:45:40 | |
# release_0.0.4
| 序号 | 变更类型 | 说明 | 时间 | 备注 |
|:---|:---|:---|:---|:--|
| 1 | A | 简单锁的实现,优化 redisLock 实现策略 | 2022-04-17 14:45:40 | |
# release_1.0.0
| 序号 | 变更类型 | 说明 | 时间 | 备注 |
|:---|:---|:---|:---|:--|
| 1 | A | 基于 redis 实现的分布式锁策略 | 2022-12-7 14:45:40 | |
# release_1.1.0
| 序号 | 变更类型 | 说明 | 时间 | 备注 |
|:---|:---|:---|:---|:--|
| 1 | A | 整合 spring | 2022-12-7 14:45:40 | |

138
README.md
View File

@@ -10,13 +10,17 @@
- 基于 redis 的分布式锁
- 基于 oracle 的分布式锁
- 整合 spring
- 基于 mysql 的分布式锁
- 整合 spring-boot
- 开箱即用,支持注解。
- 支持多种 redis 的声明方式
# 变更日志
> [变更日志](doc/CHANGELOG.md)
> [变更日志](CHANGELOG.md)
# 快速开始
@@ -32,7 +36,7 @@ maven 3.x+
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>lock-core</artifactId>
<version>${最新版本}</version>
<version>1.1.0</version>
</dependency>
```
@@ -41,36 +45,124 @@ maven 3.x+
基于本地 redis 的测试案例。
```java
Jedis jedis = new Jedis("127.0.0.1", 6379);
IOperator operator = new JedisOperator(jedis);
// 获取锁
ILock lock = LockRedisBs.newInstance().operator(operator).lock();
ILock lock = LockBs.newInstance()
.init();
String key = "ddd";
try {
boolean lockResult = lock.tryLock();
System.out.println(lockResult);
// 业务处理
// 加锁
lock.tryLock(key);
System.out.println("业务处理");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
lock.unlock();
// 释放锁
lock.unlock(key);
}
```
# 整合 spring
## maven 引入
```xml
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>lock-spring</artifactId>
<version>1.1.0</version>
</dependency>
```
## 指定 bean 使用
### 启用分布式锁
`@EnableLock` 启用分布式锁。
```xml
@Configurable
@ComponentScan(basePackages = "com.github.houbb.lock.test.service")
@EnableLock
public class SpringConfig {
}
```
### 使用 LockBs
我们可以直接 `LockBs` 的引导类。
```java
@ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringServiceRawTest {
@Autowired
private UserService userService;
@Autowired
private LockBs lockBs;
@Test
public void queryLogTest() {
final String key = "name";
try {
lockBs.tryLock(key);
final String value = userService.rawUserName(1L);
} catch (Exception exception) {
throw new RuntimeException(exception);
} finally {
lockBs.unlock(key);
}
}
}
```
## aop 注解使用
### 指定方法注解
当然,我们可以在方法上直接指定注解 `@Lock`,使用更加方便。
支持 SPEL 表达式。
```java
@Service
public class UserService {
@Lock
public String queryUserName(Long userId) {
}
@Lock(value = "#user.name")
public void queryUserName2(User user) {
}
}
```
直接使用AOP 切面生效即可。
# springboot 整合
## maven 引入
```xml
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>lock-springboot-starter</artifactId>
<version>1.1.0</version>
</dependency>
```
## 使用
同 spring
# 后期 Road-MAP
- [ ] 支持锁的可重入
持有锁的线程可以多次获取锁
- [ ] redis 实现的支持
cluster 支持
redis 支持
aliyun-redis 支持
各种各样的声明方式的默认支持
- [x] 分布式锁注解支持

View File

@@ -5,11 +5,21 @@
<parent>
<artifactId>lock</artifactId>
<groupId>com.github.houbb</groupId>
<version>0.0.1</version>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lock-api</artifactId>
<dependencies>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>common-cache-api</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>id-api</artifactId>
</dependency>
</dependencies>
</project>
</project>

View File

@@ -1,29 +1,27 @@
package com.github.houbb.lock.api.core;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
/**
* 定义
* 分布式锁接口定义
* @author binbin.hou
* @since 0.0.1
*/
public interface ILock extends Lock {
public interface ILock {
/**
* 尝试加锁
* 尝试加锁,如果失败,会一直尝试。
*
* @param time 时间
* @param unit 当为
* @param key key
* @return 返回
* @throws InterruptedException 异常
* @since 0.0.1
*/
boolean tryLock(long time, TimeUnit unit,
String key) throws InterruptedException;
boolean tryLock(long time, TimeUnit unit, String key);
/**
* 尝试加锁
* 尝试加锁,只加锁一次
* @param key key
* @return 返回
* @since 0.0.1
@@ -35,6 +33,6 @@ public interface ILock extends Lock {
* @param key key
* @since 0.0.1
*/
void unlock(String key);
boolean unlock(String key);
}

View File

@@ -0,0 +1,41 @@
package com.github.houbb.lock.api.core;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁接口定义
* @author binbin.hou
* @since 0.0.1
*/
public interface ILockSupport {
/**
* 尝试加锁,如果失败,会一直尝试。
*
* @param time 时间
* @param unit 单位
* @param key key
* @param context 上下文
* @return 返回
* @since 0.0.1
*/
boolean tryLock(long time, TimeUnit unit, String key, final ILockSupportContext context);
/**
* 尝试加锁,只加锁一次
* @param key key
* @param context 上下文
* @return 返回
* @since 0.0.1
*/
boolean tryLock(String key, final ILockSupportContext context);
/**
* 解锁
* @param key key
* @param context 上下文
* @since 0.0.1
*/
boolean unlock(String key, final ILockSupportContext context);
}

View File

@@ -0,0 +1,31 @@
package com.github.houbb.lock.api.core;
import com.github.houbb.common.cache.api.service.ICommonCacheService;
import com.github.houbb.id.api.Id;
/**
* 分布式锁接口定义
* @author binbin.hou
* @since 0.0.1
*/
public interface ILockSupportContext {
/**
* @return 标识策略
* @since 0.0.4
*/
Id id();
/**
* @return 缓存策略
* @since 0.0.4
*/
ICommonCacheService cache();
/**
* 锁的过期时间
* @return 结果
*/
int lockExpireMills();
}

View File

@@ -0,0 +1,29 @@
package com.github.houbb.lock.api.exception;
/**
* 加锁运行时异常
* @since 1.0.0
* @author dh
*/
public class LockException extends RuntimeException {
public LockException() {
}
public LockException(String message) {
super(message);
}
public LockException(String message, Throwable cause) {
super(message, cause);
}
public LockException(Throwable cause) {
super(cause);
}
public LockException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>lock</artifactId>
<groupId>com.github.houbb</groupId>
<version>0.0.1</version>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -32,12 +32,20 @@
<groupId>com.github.houbb</groupId>
<artifactId>heaven</artifactId>
</dependency>
<!--============================== OTHER ==============================-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<groupId>com.github.houbb</groupId>
<artifactId>log-integration</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>common-cache-core</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>redis-config-core</artifactId>
</dependency>
</dependencies>
</project>
</project>

View File

@@ -0,0 +1,131 @@
package com.github.houbb.lock.core.bs;
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.core.support.lock.LockSupportContext;
import com.github.houbb.lock.core.support.lock.RedisLockSupport;
import com.github.houbb.redis.config.core.factory.JedisRedisServiceFactory;
import java.util.concurrent.TimeUnit;
/**
* 锁引导类
*
* @author binbin.hou
* @since 0.0.4
*/
public final class LockBs implements ILock{
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
*/
private ILockSupportContext lockSupportContext = null;
public LockBs lockExpireMills(int lockExpireMills) {
this.lockExpireMills = lockExpireMills;
return this;
}
public LockBs id(Id id) {
ArgUtil.notNull(id, "id");
this.id = id;
return this;
}
public LockBs cache(ICommonCacheService cache) {
ArgUtil.notNull(cache, "cache");
this.cache = cache;
return this;
}
public LockBs lockSupport(ILockSupport lockSupport) {
ArgUtil.notNull(lockSupport, "lockSupport");
this.lockSupport = lockSupport;
return this;
}
/**
* 初始化
*/
public LockBs init() {
this.lockSupportContext = LockSupportContext.newInstance()
.id(id)
.cache(cache)
.lockExpireMills(lockExpireMills);
return this;
}
@Override
public boolean tryLock(long time, TimeUnit unit, String key) {
ArgUtil.notEmpty(key, "key");
this.checkInitStatus();
return this.lockSupport.tryLock(time, unit, key, lockSupportContext);
}
@Override
public boolean tryLock(String key) {
ArgUtil.notEmpty(key, "key");
this.checkInitStatus();
return this.lockSupport.tryLock(key, lockSupportContext);
}
@Override
public boolean unlock(String key) {
ArgUtil.notEmpty(key, "key");
this.checkInitStatus();
return this.lockSupport.unlock(key, lockSupportContext);
}
private void checkInitStatus() {
ArgUtil.notNull(lockSupportContext, "please init() first!");
}
}

View File

@@ -0,0 +1,28 @@
package com.github.houbb.lock.core.constant;
/**
* 通用锁常量
*
* @author binbin.hou
* @since 0.0.3
*/
public final class LockConst {
private LockConst() {
}
/**
* 默认的失效时间
*
* 暂时定为 1min
* @since 0.0.1
*/
public static final int DEFAULT_EXPIRE_MILLS = 1000 * 60;
/**
* 默认锁为全局锁
* @since 0.0.1
*/
public static final String DEFAULT_KEY = "GLOBAL";
}

View File

@@ -0,0 +1 @@
package com.github.houbb.lock.core;

View File

@@ -0,0 +1,65 @@
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.ILockSupportContext;
/**
* 分布式锁接口定义
* @author binbin.hou
* @since 0.0.1
*/
public class LockSupportContext implements ILockSupportContext {
public static LockSupportContext newInstance() {
return new LockSupportContext();
}
/**
* 标识策略
* @since 0.0.4
*/
private Id id;
/**
* 缓存策略
* @since 0.0.4
*/
private ICommonCacheService commonCacheService;
/**
* 锁的过期时间
* @since 1.0.0
*/
private int lockExpireMills;
@Override
public Id id() {
return id;
}
public LockSupportContext id(Id id) {
this.id = id;
return this;
}
@Override
public ICommonCacheService cache() {
return commonCacheService;
}
public LockSupportContext cache(ICommonCacheService commonCacheService) {
this.commonCacheService = commonCacheService;
return this;
}
@Override
public int lockExpireMills() {
return lockExpireMills;
}
public LockSupportContext lockExpireMills(int lockExpireMills) {
this.lockExpireMills = lockExpireMills;
return this;
}
}

View File

@@ -0,0 +1,86 @@
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.id.core.util.IdThreadLocalHelper;
import com.github.houbb.lock.api.core.ILockSupport;
import com.github.houbb.lock.api.core.ILockSupportContext;
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;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁接口定义
* @author binbin.hou
* @since 0.0.1
*/
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) {
long startTimeMills = System.currentTimeMillis();
// 一次获取,直接成功
boolean result = this.tryLock(key, context);
if(result) {
return true;
}
// 时间判断
if(time <= 0) {
return false;
}
long durationMills = unit.toMillis(time);
long endMills = startTimeMills + durationMills;
// 循环等待
while (System.currentTimeMillis() < endMills) {
result = tryLock(key, context);
if(result) {
return true;
}
// 等待 1ms
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return false;
}
@Override
public boolean tryLock(String key, ILockSupportContext context) {
// 生成当前线程的唯一标识
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();
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);
return JedisConst.OK.equalsIgnoreCase(result);
}
@Override
public boolean unlock(String key, ILockSupportContext context) {
String requestId = IdThreadLocalHelper.get();
log.info("[LOCK] BEGIN UN LOCK key: {} requestId: {}", key, requestId);
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));
log.info("[LOCK] END UN LOCK key: {}, requestId: {}, result: {}", key, requestId, result);
return JedisConst.RELEASE_SUCCESS.equals(result);
}
}

View File

@@ -0,0 +1,5 @@
/**
* @author binbin.hou
* @since 1.0.0
*/
package com.github.houbb.lock.core.support;

View File

@@ -1,71 +0,0 @@
package com.github.houbb.lock.redis.bs;
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.redis.core.LockRedis;
import com.github.houbb.lock.redis.support.operator.IOperator;
import com.github.houbb.wait.api.IWait;
import com.github.houbb.wait.core.Waits;
/**
* 引导类
* @author binbin.hou
* @since 0.0.1
*/
public final class LockRedisBs {
private LockRedisBs(){}
/**
* 等待实现
* @since 0.0.1
*/
private IWait wait = Waits.threadSleep();
/**
* 等待实现
* @since 0.0.1
*/
private Id id = Ids.uuid32();
/**
* 操作类
* @since 0.0.1
*/
private IOperator operator;
/**
* 新建对象实例
* @return 对象实例
* @since 0.0.1
*/
public static LockRedisBs newInstance() {
return new LockRedisBs();
}
public LockRedisBs wait(IWait wait) {
this.wait = wait;
return this;
}
public LockRedisBs id(Id id) {
this.id = id;
return this;
}
public LockRedisBs operator(IOperator operator) {
this.operator = operator;
return this;
}
/**
* 创建锁
* @return 锁
* @since 0.0.1
*/
public ILock lock() {
return new LockRedis(wait, operator, id);
}
}

View File

@@ -1,56 +0,0 @@
package com.github.houbb.lock.redis.constant;
/**
* redis 锁常量
*
* @author binbin.hou
* @since 0.0.1
*/
public final class LockRedisConst {
private LockRedisConst() {
}
/**
* 加锁成功
* @since 0.0.1
*/
public static final String LOCK_SUCCESS = "OK";
/**
* 如果不存在则设置值
* @since 0.0.1
*/
public static final String SET_IF_NOT_EXIST = "NX";
/**
* 设置过期时间
*
* 单位milliseconds
* @since 0.0.1
*/
public static final String SET_WITH_EXPIRE_TIME = "PX";
/**
* 解锁成功
*
* @since 0.0.1
*/
public static final Long RELEASE_SUCCESS = 1L;
/**
* 默认的失效时间
*
* 暂时定为 30min
* @since 0.0.1
*/
public static final int DEFAULT_EXPIRE_MILLS = 1000 * 60 * 30;
/**
* 默认锁为全局锁
* @since 0.0.1
*/
public static final String DEFAULT_KEY = "GLOBAL";
}

View File

@@ -1,87 +0,0 @@
package com.github.houbb.lock.redis.core;
import com.github.houbb.lock.api.core.ILock;
import com.github.houbb.lock.redis.constant.LockRedisConst;
import com.github.houbb.wait.api.IWait;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
/**
* 抽象实现
* @author binbin.hou
* @since 0.0.1
*/
public abstract class AbstractLockRedis implements ILock {
/**
* 锁等待
* @since 0.0.1
*/
private final IWait wait;
protected AbstractLockRedis(IWait wait) {
this.wait = wait;
}
@Override
public void lock() {
throw new UnsupportedOperationException();
}
@Override
public void lockInterruptibly() throws InterruptedException {
throw new UnsupportedOperationException();
}
@Override
public boolean tryLock() {
return tryLock(LockRedisConst.DEFAULT_KEY);
}
@Override
public void unlock() {
unlock(LockRedisConst.DEFAULT_KEY);
}
@Override
public boolean tryLock(long time, TimeUnit unit, String key) throws InterruptedException {
long startTimeMills = System.currentTimeMillis();
// 一次获取,直接成功
boolean result = this.tryLock(key);
if(result) {
return true;
}
// 时间判断
if(time <= 0) {
return false;
}
long durationMills = unit.toMillis(time);
long endMills = startTimeMills + durationMills;
// 循环等待
while (System.currentTimeMillis() < endMills) {
result = tryLock(key);
if(result) {
return true;
}
// 等待 10ms
wait.wait(TimeUnit.MILLISECONDS, 10);
}
return false;
}
@Override
public synchronized boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return tryLock(time, unit, LockRedisConst.DEFAULT_KEY);
}
@Override
public Condition newCondition() {
throw new UnsupportedOperationException();
}
}

View File

@@ -1,60 +0,0 @@
package com.github.houbb.lock.redis.core;
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.redis.constant.LockRedisConst;
import com.github.houbb.lock.redis.exception.LockRedisException;
import com.github.houbb.lock.redis.support.operator.IOperator;
import com.github.houbb.wait.api.IWait;
/**
* 这里是基于 redis 实现
*
* 实际上也可以基于 zk/数据库等实现。
*
* @author binbin.hou
* @since 0.0.1
*/
public class LockRedis extends AbstractLockRedis {
/**
* redis 操作实现
* @since 0.0.1
*/
private final IOperator redisOperator;
/**
* 主键标识
* @since 0.0.1
*/
private final Id id;
public LockRedis(IWait wait, IOperator redisOperator, Id id) {
super(wait);
this.redisOperator = redisOperator;
this.id = id;
}
@Override
public boolean tryLock(String key) {
final String requestId = id.id();
IdThreadLocalHelper.put(requestId);
return redisOperator.lock(key, requestId, LockRedisConst.DEFAULT_EXPIRE_MILLS);
}
@Override
public void unlock(String key) {
final String requestId = IdThreadLocalHelper.get();
if(StringUtil.isEmpty(requestId)) {
String threadName = Thread.currentThread().getName();
throw new LockRedisException("Thread " + threadName +" not contains requestId");
}
boolean unlock = redisOperator.unlock(key, requestId);
if(!unlock) {
throw new LockRedisException("Unlock key " + key + " result is failed!");
}
}
}

View File

@@ -1,27 +0,0 @@
package com.github.houbb.lock.redis.exception;
/**
* @author binbin.hou
* @since 0.0.1
*/
public class LockRedisException extends RuntimeException {
public LockRedisException() {
}
public LockRedisException(String message) {
super(message);
}
public LockRedisException(String message, Throwable cause) {
super(message, cause);
}
public LockRedisException(Throwable cause) {
super(cause);
}
public LockRedisException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@@ -1 +0,0 @@
package com.github.houbb.lock.redis;

View File

@@ -1,30 +0,0 @@
package com.github.houbb.lock.redis.support.operator;
/**
* Redis 客户端
* @author binbin.hou
* @since 0.0.1
*/
public interface IOperator {
/**
* 尝试获取分布式锁
*
* @param lockKey 锁
* @param requestId 请求标识
* @param expireTimeMills 超期时间
* @return 是否获取成功
* @since 0.0.1
*/
boolean lock(String lockKey, String requestId, int expireTimeMills);
/**
* 解锁
* @param lockKey 锁 key
* @param requestId 请求标识
* @return 结果
* @since 0.0.1
*/
boolean unlock(String lockKey, String requestId);
}

View File

@@ -1,63 +0,0 @@
package com.github.houbb.lock.redis.support.operator.impl;
import com.github.houbb.lock.redis.constant.LockRedisConst;
import com.github.houbb.lock.redis.support.operator.IOperator;
import redis.clients.jedis.Jedis;
import java.util.Collections;
/**
* Redis 客户端
* @author binbin.hou
* @since 0.0.1
*/
public class JedisOperator implements IOperator {
/**
* jedis 客户端
* @since 0.0.1
*/
private final Jedis jedis;
public JedisOperator(Jedis jedis) {
this.jedis = jedis;
}
/**
* 尝试获取分布式锁
*
* expireTimeMills 保证当前进程挂掉,也能释放锁
*
* requestId 保证解锁的是当前进程(锁的持有者)
*
* @param lockKey 锁
* @param requestId 请求标识
* @param expireTimeMills 超期时间
* @return 是否获取成功
* @since 0.0.1
*/
@Override
public boolean lock(String lockKey, String requestId, int expireTimeMills) {
String result = jedis.set(lockKey, requestId, LockRedisConst.SET_IF_NOT_EXIST, LockRedisConst.SET_WITH_EXPIRE_TIME, expireTimeMills);
return LockRedisConst.LOCK_SUCCESS.equals(result);
}
/**
* 解锁
*
* 1使用 requestId保证为当前锁的持有者
* 2使用 lua 脚本,保证执行的原子性。
*
* @param lockKey 锁 key
* @param requestId 请求标识
* @return 结果
* @since 0.0.1
*/
@Override
public boolean unlock(String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
return LockRedisConst.RELEASE_SUCCESS.equals(result);
}
}

View File

@@ -1 +0,0 @@
package com.github.houbb.lock.redis.support;

35
lock-spring/pom.xml Normal file
View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>lock</artifactId>
<groupId>com.github.houbb</groupId>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lock-spring</artifactId>
<dependencies>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>lock-core</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>aop-core</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>aop-spring</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>redis-config-spring</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,46 @@
package com.github.houbb.lock.spring.annotation;
import com.github.houbb.lock.spring.config.LockAopConfig;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 启用注解
* @author binbin.hou
* @since 0.0.2
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(LockAopConfig.class)
@EnableAspectJAutoProxy
public @interface EnableLock {
/**
* 加锁过期时间
* @return 时间
* @since 1.1.0
*/
int lockExpireMills() default 60 * 1000;
/**
* 唯一标识生成策略
* @return 结果
* @since 1.1.0
*/
String id() default "lockId";
/**
* 缓存实现策略 bean 名称
*
* 默认引入 redis-config 中的配置
*
* @return 实现
* @since 1.1.0
*/
String cache() default "springRedisService";
}

View File

@@ -0,0 +1,28 @@
package com.github.houbb.lock.spring.annotation;
import java.lang.annotation.*;
/**
* 分布式加锁注解
* @author binbin.hou
* @since 0.0.2
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Lock {
/**
* 缓存的 key 策略,支持 SpEL
* @return 结果
*/
String value() default "";
/**
* 尝试获取锁等待时间
* @return 结果
*/
long tryLockMills() default 10 * 1000;
}

View File

@@ -0,0 +1,147 @@
package com.github.houbb.lock.spring.aop;
import com.github.houbb.aop.spring.util.SpringAopUtil;
import com.github.houbb.heaven.util.lang.ObjectUtil;
import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.heaven.util.util.ArrayUtil;
import com.github.houbb.lock.api.exception.LockException;
import com.github.houbb.lock.core.bs.LockBs;
import com.github.houbb.lock.spring.annotation.Lock;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
/**
* @author binbin.hou
* @since 1.1.0
*/
@Aspect
@Component
public class LockAspect {
private final Log log = LogFactory.getLog(LockAspect.class);
@Autowired
@Qualifier("lockBs")
private LockBs lockBs;
@Pointcut("@annotation(com.github.houbb.lock.spring.annotation.Lock)")
public void lockPointcut() {
}
/**
* 执行核心方法
*
* 相当于 MethodInterceptor
* @param point 切点
* @return 结果
* @throws Throwable 异常信息
* @since 0.0.2
*/
@Around("lockPointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
Method method = SpringAopUtil.getCurrentMethod(point);
boolean isLockAnnotation = method.isAnnotationPresent(Lock.class);
if(isLockAnnotation) {
Lock lock = method.getAnnotation(Lock.class);
// 如果构建 key
String lockKey = buildLockKey(lock, point);
boolean tryLockFlag = false;
try {
long tryLockMills = lock.tryLockMills();
tryLockFlag = lockBs.tryLock(tryLockMills, TimeUnit.MILLISECONDS, lockKey);
if(!tryLockFlag) {
log.warn("[LOCK] TRY LOCK FAILED {}", lockKey);
throw new LockException("[LOCK] TRY LOCK FAILED " + lockKey);
}
// 执行业务
return point.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
// 只有获取锁的情况下,才尝试释放锁
if(tryLockFlag) {
boolean unLockFlag = lockBs.unlock(lockKey);
// 异常处理等
}
}
} else {
return point.proceed();
}
}
/**
* 构建加锁的 key
*
* https://www.cnblogs.com/fashflying/p/6908028.html spring cache
*
* https://www.cnblogs.com/best/p/5748105.html SpEL
* @param lock 注解信息
* @param joinPoint 参数
* @return 结果
*/
private String buildLockKey(Lock lock,
ProceedingJoinPoint joinPoint) {
final Object[] args = joinPoint.getArgs();
final String lockValue = lock.value();
//创建SpEL表达式的解析器
ExpressionParser parser = new SpelExpressionParser();
//1. 如果没有入参怎么办?
if(ArrayUtil.isEmpty(args)) {
log.warn("[LOCK] method args is empty, return lock.value() {}", lockValue);
return lockValue;
}
// 如果 lockValue 的值为空呢?
if(StringUtil.isEmpty(lockValue)) {
return Arrays.toString(args);
}
// 如何获取参数名称呢?
//解析表达式需要的上下文,解析时有一个默认的上下文
// jdk1.7 之前,直接使用 arg0, arg1...
EvaluationContext ctx = new StandardEvaluationContext();
// 利用 spring 的处理方式
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
String[] paramNameList = methodSignature.getParameterNames();
for(int i = 0; i < paramNameList.length; i++) {
String paramName = paramNameList[i];
Object paramValue = args[i];
//在上下文中设置变量变量名为user内容为user对象
ctx.setVariable(paramName, paramValue);
}
// 直接 toString比较简单。
Object value = parser.parseExpression(lockValue).getValue(ctx);
return ObjectUtil.objectToString(value, "null");
}
}

View File

@@ -0,0 +1,16 @@
package com.github.houbb.lock.spring.config;
import com.github.houbb.redis.config.spring.annotation.EnableRedisConfig;
import org.springframework.context.annotation.Configuration;
/**
* bean 配置
*
* @author binbin.hou
* @since 0.0.2
*/
@Configuration
@EnableRedisConfig
public class CommonCacheConfig {
}

View File

@@ -0,0 +1,69 @@
package com.github.houbb.lock.spring.config;
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.core.Ids;
import com.github.houbb.lock.core.bs.LockBs;
import com.github.houbb.lock.spring.annotation.EnableLock;
import com.github.houbb.redis.config.core.factory.JedisRedisServiceFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
/**
* aop 配置
*
* @author binbin.hou
* @since 0.0.2
*/
@Configuration
@ComponentScan(basePackages = "com.github.houbb.lock.spring")
@Import({LockBeanConfig.class, CommonCacheConfig.class})
public class LockAopConfig implements ImportAware, BeanFactoryPostProcessor {
@Bean("lockBs")
public LockBs lockBs() {
int lockExpireMills = (int) enableLockAttributes.get("lockExpireMills");
ICommonCacheService commonCacheService = beanFactory.getBean(enableLockAttributes.getString("cache"), ICommonCacheService.class);
Id id = beanFactory.getBean(enableLockAttributes.getString("id"), Id.class);
return LockBs.newInstance()
.cache(commonCacheService)
.id(id)
.lockExpireMills(lockExpireMills)
.init();
}
/**
* 属性信息
*/
private AnnotationAttributes enableLockAttributes;
/**
* bean 工厂
*
* @since 0.0.5
*/
private ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setImportMetadata(AnnotationMetadata annotationMetadata) {
enableLockAttributes = AnnotationAttributes.fromMap(
annotationMetadata.getAnnotationAttributes(EnableLock.class.getName(), false));
if (enableLockAttributes == null) {
throw new IllegalArgumentException(
"@EnableLock is not present on importing class " + annotationMetadata.getClassName());
}
}
}

View File

@@ -0,0 +1,24 @@
package com.github.houbb.lock.spring.config;
import com.github.houbb.id.api.Id;
import com.github.houbb.id.core.core.Ids;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* bean 配置
*
* @author binbin.hou
* @since 0.0.2
*/
@Configuration
@ComponentScan(basePackages = "com.github.houbb.lock.spring")
public class LockBeanConfig {
@Bean("lockId")
public Id lockId() {
return Ids.uuid32();
}
}

View File

@@ -0,0 +1 @@
package com.github.houbb.lock.spring;

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>lock</artifactId>
<groupId>com.github.houbb</groupId>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lock-springboot-starter</artifactId>
<dependencies>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>lock-spring</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,18 @@
package com.github.houbb.lock.springboot.starter.config;
import com.github.houbb.lock.spring.annotation.EnableLock;
import com.github.houbb.lock.spring.config.LockAopConfig;
import com.github.houbb.redis.config.spring.annotation.EnableRedisConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
/**
* 分布式锁自动配置
* @author binbin.hou
* @since 1.0.0
*/
@Configuration
@ConditionalOnClass(LockAutoConfig.class)
@EnableLock
public class LockAutoConfig {
}

View File

@@ -0,0 +1,5 @@
/**
* @author d
* @since 1.0.0
*/
package com.github.houbb.lock.springboot.starter;

View File

@@ -0,0 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.github.houbb.lock.springboot.starter.config.LockAutoConfig

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>lock</artifactId>
<groupId>com.github.houbb</groupId>
<version>0.0.1</version>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -16,11 +16,37 @@
<groupId>com.github.houbb</groupId>
<artifactId>lock-core</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>lock-spring</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>test-spring</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>slf4j-common</artifactId>
<version>1.0.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.11</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.11</version>
</dependency>
</dependencies>
</project>
</project>

View File

@@ -0,0 +1,18 @@
package com.github.houbb.lock.test;
/**
* @author binbin.hou
* @since 0.0.1
*/
public class SyncTest {
public synchronized void syncOne() {
System.out.println("方法1执行");
syncTwo();
}
public synchronized void syncTwo() {
System.out.println("方法2执行");
}
}

View File

@@ -0,0 +1,16 @@
package com.github.houbb.lock.test.config;
import com.github.houbb.lock.spring.annotation.EnableLock;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
/**
* @author binbin.hou
* @since 1.0.0
*/
@Configurable
@ComponentScan(basePackages = "com.github.houbb.lock.test.service")
@EnableLock
public class SpringConfig {
}

View File

@@ -0,0 +1,33 @@
package com.github.houbb.lock.test.model;
public class User {
private String name;
private String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
'}';
}
}

View File

@@ -0,0 +1 @@
package com.github.houbb.lock.test;

View File

@@ -0,0 +1,27 @@
package com.github.houbb.lock.test.service;
import com.github.houbb.lock.spring.annotation.Lock;
import com.github.houbb.lock.test.model.User;
import org.springframework.stereotype.Service;
/**
* @author binbin.hou
* @since 1.0.0
*/
@Service
public class UserService {
public String rawUserName(Long userId) {
return userId+"-name";
}
@Lock
public String queryUserName(Long userId) {
return userId+"-name";
}
@Lock(value = "#user.name")
public void queryUserName2(User user) {
System.out.println("user: " + user.toString());
}
}

View File

@@ -1,35 +0,0 @@
package com.github.houbb.lock.test;
import com.github.houbb.lock.api.core.ILock;
import com.github.houbb.lock.redis.bs.LockRedisBs;
import com.github.houbb.lock.redis.support.operator.IOperator;
import com.github.houbb.lock.redis.support.operator.impl.JedisOperator;
import org.junit.Test;
import redis.clients.jedis.Jedis;
/**
* @author binbin.hou
* @since 0.0.1
*/
public class RedisLockTest {
@Test
public void helloTest() {
Jedis jedis = new Jedis("127.0.0.1", 6379);
IOperator operator = new JedisOperator(jedis);
// 获取锁
ILock lock = LockRedisBs.newInstance().operator(operator).lock();
try {
boolean lockResult = lock.tryLock();
System.out.println(lockResult);
// 业务处理
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}

View File

@@ -0,0 +1,28 @@
package com.github.houbb.lock.test.core;
import com.github.houbb.lock.api.core.ILock;
import com.github.houbb.lock.core.bs.LockBs;
import org.junit.Test;
public class LockBsTest {
@Test
public void helloTest() {
ILock lock = LockBs.newInstance()
.init();
String key = "ddd";
try {
// 加锁
lock.tryLock(key);
System.out.println("业务处理");
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 释放锁
lock.unlock(key);
}
}
}

View File

@@ -1,6 +1,7 @@
package com.github.houbb.lock.test;
package com.github.houbb.lock.test.redis;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import redis.clients.jedis.Jedis;
@@ -8,6 +9,7 @@ import redis.clients.jedis.Jedis;
* @author binbin.hou
* @since 0.0.1
*/
@Ignore
public class JedisTest {
@Test

View File

@@ -0,0 +1,37 @@
//package com.github.houbb.lock.test.redis;
//
//import com.github.houbb.lock.api.core.ILock;
//import com.github.houbb.lock.api.support.IOperator;
//import com.github.houbb.lock.core.bs.LockBs;
//import com.github.houbb.lock.redis.support.operator.JedisOperator;
//import org.junit.Ignore;
//import org.junit.Test;
//import redis.clients.jedis.Jedis;
//
///**
// * @author binbin.hou
// * @since 0.0.1
// */
//@Ignore
//public class LockRedisTest {
//
// @Test
// public void helloTest() {
// Jedis jedis = new Jedis("127.0.0.1", 6379);
// IOperator operator = new JedisOperator(jedis);
//
// // 获取锁
// ILock lock = LockBs.newInstance(operator).lock();
//
// try {
// boolean lockResult = lock.tryLock();
// System.out.println(lockResult);
// // 业务处理
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// lock.unlock();
// }
// }
//
//}

View File

@@ -0,0 +1,41 @@
package com.github.houbb.lock.test.spring;
import com.github.houbb.lock.core.bs.LockBs;
import com.github.houbb.lock.test.config.SpringConfig;
import com.github.houbb.lock.test.model.User;
import com.github.houbb.lock.test.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author binbin.hou
* @since 1.0.0
*/
@ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringServiceRawTest {
@Autowired
private UserService userService;
@Autowired
private LockBs lockBs;
@Test
public void queryLogTest() {
final String key = "name";
try {
lockBs.tryLock(key);
final String value = userService.rawUserName(1L);
} catch (Exception exception) {
throw new RuntimeException(exception);
} finally {
lockBs.unlock(key);
}
}
}

View File

@@ -0,0 +1,38 @@
package com.github.houbb.lock.test.spring;
import com.github.houbb.lock.test.config.SpringConfig;
import com.github.houbb.lock.test.model.User;
import com.github.houbb.lock.test.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author binbin.hou
* @since 1.0.0
*/
@ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringServiceTest {
@Autowired
private UserService userService;
@Test
public void queryLogTest() {
final String key = "name";
final String value = userService.queryUserName(1L);
}
@Test
public void queryUserNameTest() {
User user = new User();
user.setId("001");
user.setName("u-001");
userService.queryUserName2(user);
}
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 /app/sv/logs -->
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!--com.github.houbb 包路径 additivity 表示是否 想上层传递)-->
<logger name="com.github.houbb.lock" level="INFO" additivity="true">
</logger>
<!-- 日志输出级别-->
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>

47
lock-test2/pom.xml Normal file
View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>lock</artifactId>
<groupId>com.github.houbb</groupId>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lock-test2</artifactId>
<dependencies>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>lock-springboot-starter</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>test-spring</artifactId>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>slf4j-common</artifactId>
<version>1.0.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.11</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.11</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,5 @@
/**
* @author d
* @since 1.0.0
*/
package com.github.houbb.lock.test2;

View File

@@ -0,0 +1,17 @@
package com.github.houbb.lock.test2.service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author binbin.hou
* @since 0.0.3
*/
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

View File

@@ -0,0 +1,18 @@
package com.github.houbb.lock.test2.service;
import com.github.houbb.lock.spring.annotation.Lock;
import org.springframework.stereotype.Service;
/**
* @author binbin.hou
* @since 0.0.1
*/
@Service
public class UserService {
@Lock
public void queryInfo(final String id) {
System.out.println("query info: " + id);
}
}

View File

@@ -0,0 +1,25 @@
package com.github.houbb.lock.test2.service;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author binbin.hou
* @since 0.0.2
*/
@ContextConfiguration(classes = MyApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceTest {
@Autowired
private UserService service;
@Test
public void queryTest() {
service.queryInfo("1");
}
}

View File

@@ -0,0 +1,5 @@
/**
* @author d
* @since 1.0.0
*/
package com.github.houbb.lock.test2.service;

81
pom.xml
View File

@@ -5,11 +5,14 @@
<groupId>com.github.houbb</groupId>
<artifactId>lock</artifactId>
<packaging>pom</packaging>
<version>0.0.1</version>
<version>1.1.0</version>
<modules>
<module>lock-api</module>
<module>lock-core</module>
<module>lock-test</module>
<module>lock-spring</module>
<module>lock-springboot-starter</module>
<module>lock-test2</module>
</modules>
<properties>
@@ -33,13 +36,19 @@
<!--============================== INTER ==============================-->
<plugin.gen.version>1.0.6</plugin.gen.version>
<heaven.version>0.1.114</heaven.version>
<heaven.version>0.1.167</heaven.version>
<id.version>0.0.6</id.version>
<wait.version>0.0.1</wait.version>
<log-integration.version>1.1.8</log-integration.version>
<common-cache.version>0.0.5</common-cache.version>
<redis-config.version>1.4.0</redis-config.version>
<aop.version>0.0.2</aop.version>
<test.version>0.0.1</test.version>
<!--============================== OTHER ==============================-->
<junit.version>4.12</junit.version>
<jedis.version>2.8.1</jedis.version>
<spring-boot.version>1.5.22.RELEASE</spring-boot.version>
</properties>
<dependencyManagement>
@@ -55,6 +64,16 @@
<artifactId>lock-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>lock-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>lock-springboot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<!--============================== INTER ==============================-->
<dependency>
@@ -62,6 +81,11 @@
<artifactId>heaven</artifactId>
<version>${heaven.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>id-api</artifactId>
<version>${id.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>id-core</artifactId>
@@ -72,6 +96,33 @@
<artifactId>wait</artifactId>
<version>${wait.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>log-integration</artifactId>
<version>${log-integration.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>common-cache-api</artifactId>
<version>${common-cache.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>common-cache-core</artifactId>
<version>${common-cache.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>redis-config-core</artifactId>
<version>${redis-config.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>redis-config-spring</artifactId>
<version>${redis-config.version}</version>
</dependency>
<!--============================== OTHER ==============================-->
<dependency>
@@ -83,10 +134,28 @@
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
<groupId>com.github.houbb</groupId>
<artifactId>aop-core</artifactId>
<version>${aop.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>aop-spring</artifactId>
<version>${aop.version}</version>
</dependency>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>test-spring</artifactId>
<version>${test.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -10,9 +10,9 @@ ECHO "============================= RELEASE START..."
:: 版本号信息(需要手动指定)
:::: 旧版本名称
SET version=0.0.1
SET version=1.1.0
:::: 新版本名称
SET newVersion=0.0.2
SET newVersion=1.2.0
:::: 组织名称
SET groupName=com.github.houbb
:::: 项目名称