Skip to content

Commit

Permalink
🎉 add DistributedLock
Browse files Browse the repository at this point in the history
  • Loading branch information
weihubeats committed Mar 16, 2024
1 parent 2bcea73 commit eef5a37
Show file tree
Hide file tree
Showing 16 changed files with 564 additions and 2 deletions.
3 changes: 2 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
<module>spring-boot-nebula-mybatis</module>
<module>spring-boot-nebula-aop-base</module>
<module>spring-boot-nebula-distribute-lock</module>
</modules>
<module>spring-boot-nebula-web-common</module>
</modules>

<name>spring-boot-nebula</name>
<description>spring-boot-common</description>
Expand Down
13 changes: 13 additions & 0 deletions spring-boot-nebula-dependencies/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<commons-collections4.version>4.4</commons-collections4.version>
<javers-core.version>6.6.5</javers-core.version>
<mybatis-plus-boot-starter.version>3.5.5</mybatis-plus-boot-starter.version>
<redission.version>3.17.3</redission.version>
</properties>


Expand Down Expand Up @@ -65,6 +66,12 @@
<version>${revision}</version>
</dependency>

<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>spring-boot-nebula-web-common</artifactId>
<version>${revision}</version>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
Expand All @@ -89,6 +96,12 @@
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>

<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redission.version}</version>
</dependency>


</dependencies>

Expand Down
19 changes: 18 additions & 1 deletion spring-boot-nebula-distribute-lock/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,29 @@
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>

<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>spring-boot-nebula-aop-base</artifactId>
</dependency>

<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>

<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>spring-boot-nebula-common</artifactId>
</dependency>

<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>spring-boot-nebula-web-common</artifactId>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.nebula.distribute.lock.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

/**
* @author : wh
* @date : 2024/3/13 13:49
* @description:
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NebulaDistributedLock {

/**
* 锁名字
*/
String lockName() default "";

/**
* 锁前缀
*/
String lockNamePre() default "";

/**
* 锁后缀
*/
String lockNamePost() default "";

/**
* 锁前后缀拼接分隔符
*/
String separator() default "_";

/**
* 是否使用公平锁
*/
boolean fairLock() default false;

/**
* 是否使用尝试锁
*/
boolean tryLock() default false;

/**
* 尝试锁最长等待时间
*/
long tryWaitTime() default 30L;

/**
* 锁超时时间,超时自动释放锁
*/
long outTime() default 20L;

/**
* 时间单位 默认秒
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.nebula.distribute.lock.aop;

import com.nebula.base.utils.DataUtils;
import com.nebula.distribute.lock.annotation.NebulaDistributedLock;
import com.nebula.distribute.lock.core.DistributedLock;
import com.nebula.distribute.lock.core.NebulaDistributedLockTemplate;
import com.nebula.web.common.utils.ExpressionUtil;
import java.lang.reflect.Method;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
* @author : wh
* @date : 2024/3/15 13:34
* @description:
*/
@Slf4j
public class NebulaDistributedLockAnnotationInterceptor implements MethodInterceptor {

private final NebulaDistributedLockTemplate lock;

public NebulaDistributedLockAnnotationInterceptor(NebulaDistributedLockTemplate lock) {
if (DataUtils.isEmpty(lock)) {
throw new RuntimeException("DistributedLockTemplate is null");
}
this.lock = lock;
}

@Nullable
@Override
public Object invoke(@Nonnull MethodInvocation methodInvocation) {
Method method = methodInvocation.getMethod();
NebulaDistributedLock annotation = method.getAnnotation(NebulaDistributedLock.class);
Object[] args = methodInvocation.getArguments();
String lockName = getLockName(annotation, args, method);
if (log.isDebugEnabled()) {
log.debug("lockName: {}", lockName);
}
boolean fairLock = annotation.fairLock();
if (annotation.tryLock()) {
return lock.tryLock(new DistributedLock<>() {
@Override
public Object process() {
return proceed(methodInvocation);
}

@Override
public String lockName() {
return lockName;
}
}, annotation.tryWaitTime(), annotation.outTime(), annotation.timeUnit(), fairLock);
} else {
return lock.lock(new DistributedLock<>() {
@Override
public Object process() {
return proceed(methodInvocation);
}

@Override
public String lockName() {
return lockName;
}
}, annotation.outTime(), annotation.timeUnit(), fairLock);
}
}

public Object proceed(MethodInvocation methodInvocation) {
try {
return methodInvocation.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}

}

/**
* 获取锁名字,优先获取注解中锁名
*
* @param nebulaDistributedLock
* @param args
* @param method
* @return
*/
private String getLockName(NebulaDistributedLock nebulaDistributedLock, Object[] args, Method method) {
if (DataUtils.isNotEmpty(nebulaDistributedLock.lockName())) {
return nebulaDistributedLock.lockName();
}
String lockNamePre = nebulaDistributedLock.lockNamePre();
String lockNamePost = nebulaDistributedLock.lockNamePost();
String separator = nebulaDistributedLock.separator();

if (ExpressionUtil.isEl(lockNamePre)) {
lockNamePre = (String) ExpressionUtil.parse(lockNamePre, method, args);
}
if (ExpressionUtil.isEl(lockNamePost)) {
lockNamePost = Objects.requireNonNull(ExpressionUtil.parse(lockNamePost, method, args)).toString();
}

StringBuilder sb = new StringBuilder();
if (DataUtils.isNotEmpty(lockNamePre)) {
sb.append(lockNamePre);
}
sb.append(separator);
if (DataUtils.isNotEmpty(lockNamePost)) {
sb.append(lockNamePost);
}
return sb.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.nebula.distribute.lock.autoconfigure;

import com.nebula.aop.base.NebulaBaseAnnotationAdvisor;
import com.nebula.distribute.lock.annotation.NebulaDistributedLock;
import com.nebula.distribute.lock.aop.NebulaDistributedLockAnnotationInterceptor;
import com.nebula.distribute.lock.core.NebulaDistributedLockTemplate;
import com.nebula.distribute.lock.core.RedissonDistributedLockTemplate;
import org.redisson.api.RedissonClient;
import org.springframework.aop.Advisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

/**
* @author : wh
* @date : 2024/3/15 13:39
* @description:
*/
@Configuration(proxyBeanMethods = false)
public class NebulaDistributedLockAutoConfiguration {

@Bean
public RedissonDistributedLockTemplate redissonDistributedLockTemplate(RedissonClient redissonClient) {
RedissonDistributedLockTemplate template = new RedissonDistributedLockTemplate(redissonClient);
return template;
}

@Bean
@Order(1)
public Advisor distributedLockAnnotationAdvisor(NebulaDistributedLockTemplate nebulaDistributedLockTemplate) {
NebulaDistributedLockAnnotationInterceptor advisor = new NebulaDistributedLockAnnotationInterceptor(nebulaDistributedLockTemplate);
return new NebulaBaseAnnotationAdvisor(advisor, NebulaDistributedLock.class);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.nebula.distribute.lock.core;

/**
* @author : wh
* @date : 2024/3/15 13:35
* @description:
*/
public interface DistributedLock<T> {

/**
* 分布式锁逻辑 代码块
*/
T process();

String lockName();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.nebula.distribute.lock.core;

import java.util.concurrent.TimeUnit;

/**
* @author : wh
* @date : 2024/3/15 13:35
* @description:
*/
public interface NebulaDistributedLockTemplate {

/**
* 默认超时锁释放时间
*/
long DEFAULT_OUT_TIME = 5;
/**
* 默认尝试加锁时间
*/
long DEFAULT_TRY_OUT_TIME = 30;
/**
* 默认时间单位
*/
TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS;

/**
* 加锁
* @param distributedLock
* @param fairLock 是否使用公平锁
* @param <T>
* @return
*/
<T> T lock(DistributedLock<T> distributedLock, boolean fairLock);

/**
*
* @param distributedLock
* @param outTime 锁超时时间。超时后自动释放锁
* @param timeUnit 时间单位
* @param fairLock 是否使用公平锁
* @param <T>
* @return
*/
<T> T lock(DistributedLock<T> distributedLock, long outTime, TimeUnit timeUnit, boolean fairLock);

/**
* 尝试加锁
* @param distributedLock
* @param fairLock 是否使用公平锁
* @param <T>
* @return
*/
<T> T tryLock(DistributedLock<T> distributedLock, boolean fairLock);

/**
*
* @param distributedLock
* @param tryOutTime 尝试获取锁时间
* @param outTime 锁超时时间
* @param timeUnit 时间单位
* @param fairLock 是否使用公平锁
* @param <T>
* @return
*/
<T> T tryLock(DistributedLock<T> distributedLock, long tryOutTime, long outTime, TimeUnit timeUnit, boolean fairLock);


}
Loading

0 comments on commit eef5a37

Please sign in to comment.