@@ -31,4 +31,9 @@ public @interface DLock { | |||||
* @return 锁的时间单位 | * @return 锁的时间单位 | ||||
*/ | */ | ||||
TimeUnit timeUnit() default TimeUnit.MILLISECONDS; | TimeUnit timeUnit() default TimeUnit.MILLISECONDS; | ||||
/** | |||||
* @return 快速失败,true: 限流,拿不到锁,直接失败;false: 不限流,接收所有请求,阻塞执行 | |||||
*/ | |||||
boolean fastFail() default false; | |||||
} | } |
@@ -1,7 +1,8 @@ | |||||
package com.xkcoding.distributed.lock.aop; | package com.xkcoding.distributed.lock.aop; | ||||
import com.xkcoding.distributed.lock.annotation.DLock; | import com.xkcoding.distributed.lock.annotation.DLock; | ||||
import com.xkcoding.distributed.lock.api.DistributedLockService; | |||||
import com.xkcoding.distributed.lock.api.DistributedLock; | |||||
import com.xkcoding.distributed.lock.api.DistributedLockClient; | |||||
import lombok.RequiredArgsConstructor; | import lombok.RequiredArgsConstructor; | ||||
import org.aspectj.lang.ProceedingJoinPoint; | import org.aspectj.lang.ProceedingJoinPoint; | ||||
import org.aspectj.lang.annotation.Around; | import org.aspectj.lang.annotation.Around; | ||||
@@ -27,24 +28,43 @@ import java.util.concurrent.TimeUnit; | |||||
@Aspect | @Aspect | ||||
@RequiredArgsConstructor | @RequiredArgsConstructor | ||||
public class DistributedLockAspect { | public class DistributedLockAspect { | ||||
private final DistributedLockService distributedLockService; | |||||
private final DistributedLockClient distributedLockClient; | |||||
@Around("@annotation(lock)") | |||||
public Object around(ProceedingJoinPoint pjp, DLock lock) throws Throwable { | |||||
@Around("@annotation(dLock)") | |||||
public Object around(ProceedingJoinPoint pjp, DLock dLock) throws Throwable { | |||||
Method method = ((MethodSignature) pjp.getSignature()).getMethod(); | Method method = ((MethodSignature) pjp.getSignature()).getMethod(); | ||||
Object[] args = pjp.getArgs(); | Object[] args = pjp.getArgs(); | ||||
String lockKey = lock.lockKey(); | |||||
String lockKey = dLock.lockKey(); | |||||
lockKey = parseExpression(lockKey, method, args); | lockKey = parseExpression(lockKey, method, args); | ||||
long timeout = lock.lockTime(); | |||||
TimeUnit timeUnit = lock.timeUnit(); | |||||
return distributedLockService.lock(lockKey, timeout, timeUnit, () -> { | |||||
long timeout = dLock.lockTime(); | |||||
TimeUnit timeUnit = dLock.timeUnit(); | |||||
DistributedLock lock = distributedLockClient.getLock(lockKey, timeout, timeUnit); | |||||
if (dLock.fastFail()) { | |||||
if (lock.tryLock()) { | |||||
try { | |||||
return pjp.proceed(); | |||||
} catch (Throwable t) { | |||||
throw new RuntimeException(t); | |||||
} finally { | |||||
lock.unlock(); | |||||
} | |||||
} else { | |||||
throw new RuntimeException("请勿重复提交!"); | |||||
} | |||||
} else { | |||||
lock.lock(); | |||||
try { | try { | ||||
return pjp.proceed(); | return pjp.proceed(); | ||||
} catch (Throwable e) { | |||||
throw new RuntimeException(e); | |||||
} catch (Throwable t) { | |||||
throw new RuntimeException(t); | |||||
} finally { | |||||
lock.unlock(); | |||||
} | } | ||||
}); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
@@ -16,15 +16,15 @@ public abstract class DistributedLock implements Lock { | |||||
/** | /** | ||||
* 锁的标识 | * 锁的标识 | ||||
*/ | */ | ||||
private final String lockKey; | |||||
protected final String lockKey; | |||||
/** | /** | ||||
* 锁的时间 | * 锁的时间 | ||||
*/ | */ | ||||
private final long lockTime; | |||||
protected final long lockTime; | |||||
/** | /** | ||||
* 锁的时间单位 | * 锁的时间单位 | ||||
*/ | */ | ||||
private final TimeUnit timeUnit; | |||||
protected final TimeUnit timeUnit; | |||||
protected DistributedLock(String lockKey, long lockTime, TimeUnit timeUnit) { | protected DistributedLock(String lockKey, long lockTime, TimeUnit timeUnit) { | ||||
this.lockKey = lockKey; | this.lockKey = lockKey; | ||||
@@ -1,27 +0,0 @@ | |||||
package com.xkcoding.distributed.lock.api; | |||||
import java.util.concurrent.TimeUnit; | |||||
import java.util.function.Supplier; | |||||
/** | |||||
* <p> | |||||
* 分布式锁实现 | |||||
* </p> | |||||
* | |||||
* @author yangkai.shen | |||||
* @date 2022-09-02 21:11 | |||||
*/ | |||||
public interface DistributedLockService { | |||||
/** | |||||
* 锁 | |||||
* | |||||
* @param lockKey 锁的标识 | |||||
* @param lockTime 锁的时间 | |||||
* @param timeUnit 锁的时间单位 | |||||
* @param execute 执行逻辑 | |||||
* @param <T> 返回值类型 | |||||
* @return 返回值 | |||||
*/ | |||||
<T> T lock(String lockKey, long lockTime, TimeUnit timeUnit, Supplier<T> execute); | |||||
} |
@@ -1,47 +0,0 @@ | |||||
package com.xkcoding.distributed.lock.api.impl; | |||||
import com.xkcoding.distributed.lock.api.DistributedLock; | |||||
import com.xkcoding.distributed.lock.api.DistributedLockClient; | |||||
import com.xkcoding.distributed.lock.api.DistributedLockService; | |||||
import lombok.RequiredArgsConstructor; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import java.util.concurrent.TimeUnit; | |||||
import java.util.function.Supplier; | |||||
/** | |||||
* <p> | |||||
* 分布式锁实现 | |||||
* </p> | |||||
* | |||||
* @author yangkai.shen | |||||
* @date 2022-09-02 21:41 | |||||
*/ | |||||
@Slf4j | |||||
@RequiredArgsConstructor | |||||
public class DistributedLockServiceImpl implements DistributedLockService { | |||||
private final DistributedLockClient distributedLockClient; | |||||
/** | |||||
* 锁 | |||||
* | |||||
* @param lockKey 锁 | |||||
* @param timeout 超时时间 | |||||
* @param timeUnit 超时单位 | |||||
* @param execute 执行逻辑 | |||||
* @return 返回值 | |||||
*/ | |||||
@Override | |||||
public <T> T lock(String lockKey, long timeout, TimeUnit timeUnit, Supplier<T> execute) { | |||||
DistributedLock lock = distributedLockClient.getLock(lockKey, timeout, timeUnit); | |||||
lock.lock(); | |||||
try { | |||||
return execute.get(); | |||||
} catch (Throwable t) { | |||||
throw new RuntimeException(t); | |||||
} finally { | |||||
lock.unlock(); | |||||
} | |||||
} | |||||
} |
@@ -2,8 +2,6 @@ package com.xkcoding.distributed.lock.autoconfigure; | |||||
import com.xkcoding.distributed.lock.aop.DistributedLockAspect; | import com.xkcoding.distributed.lock.aop.DistributedLockAspect; | ||||
import com.xkcoding.distributed.lock.api.DistributedLockClient; | import com.xkcoding.distributed.lock.api.DistributedLockClient; | ||||
import com.xkcoding.distributed.lock.api.DistributedLockService; | |||||
import com.xkcoding.distributed.lock.api.impl.DistributedLockServiceImpl; | |||||
import com.xkcoding.distributed.lock.api.impl.DummyDistributedLockClient; | import com.xkcoding.distributed.lock.api.impl.DummyDistributedLockClient; | ||||
import org.mybatis.spring.annotation.MapperScan; | import org.mybatis.spring.annotation.MapperScan; | ||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||||
@@ -28,12 +26,7 @@ public class DistributedLockAutoConfiguration { | |||||
} | } | ||||
@Bean | @Bean | ||||
public DistributedLockService distributedLockService(DistributedLockClient distributedLockClient) { | |||||
return new DistributedLockServiceImpl(distributedLockClient); | |||||
} | |||||
@Bean | |||||
public DistributedLockAspect distributedLockAspect(DistributedLockService distributedLockService) { | |||||
return new DistributedLockAspect(distributedLockService); | |||||
public DistributedLockAspect distributedLockAspect(DistributedLockClient distributedLockClient) { | |||||
return new DistributedLockAspect(distributedLockClient); | |||||
} | } | ||||
} | } |
@@ -26,7 +26,7 @@ public class StockService { | |||||
/** | /** | ||||
* 减货物 | * 减货物 | ||||
*/ | */ | ||||
@DLock(lockKey = "'lock_stock_'+#stockId", lockTime = 3000, timeUnit = TimeUnit.MICROSECONDS) | |||||
@DLock(lockKey = "'lock_stock_'+#stockId", lockTime = 3000, timeUnit = TimeUnit.MICROSECONDS, fastFail = false) | |||||
public void reduceStock(Long stockId) { | public void reduceStock(Long stockId) { | ||||
// 先查询库存是否充足 | // 先查询库存是否充足 | ||||
Stock stock = this.stockMapper.selectById(stockId); | Stock stock = this.stockMapper.selectById(stockId); | ||||