1.引入依赖
redisson官方说明:
https://solon.noear.org/article/533
<!-- redisson -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>redisson-solon-plugin</artifactId>
</dependency>
2.app.yml配置
redisson:
config: |
# 这里使用redis单机模式
singleServerConfig:
password:
address: redis://localhost:6379
database: 0
# 日志打印配置,redisson日志会很频繁,所以这边屏蔽掉日志,只打印错误日志
solon.logging:
logger:
"org.redisson":
level: ERROR
3.配置redissin连接对象
/**
* redisson配置类
* @Author: ajie
* @CreateTime: 2024-08-01 16:53
*/
@Configuration
public class RedisConfig {
@Bean(name = "redissonClient", typed = true) //typed 表示可类型注入 //即默认
public RedissonClient redissonClient(@Inject("${redisson}") RedissonClientOriginalSupplier supplier){
return supplier.get();
}
}
4.编写测试接口
package com.superb.controller;
import com.superb.annotation.RedissonLock;
import io.swagger.annotations.ApiOperation;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.core.handle.MethodType;
import org.noear.solon.core.handle.Result;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
/**
* @Author: ajie
* @CreateTime: 2024-08-01 17:13
*/
@Controller
@Mapping("test")
public class TestController {
private static volatile int test1 = 99;
private static volatile int test2 = 99;
private static volatile int test3 = 99;
@Inject
private RedissonClient redissonClient;
@Mapping(value = "test1", method = MethodType.GET)
@ApiOperation(value = "第一个测试方法")
public Result<?> test() {
// 获取锁
RLock lock = redissonClient.getLock("testLock");
// 加锁
lock.lock(30, TimeUnit.SECONDS);
if (test1 > 0) {
test1--;
}
//如果该线程还持有该锁,那么释放该锁。如果该线程不持有该锁,说明该线程的锁已到过期时间,自动释放锁 解决空白出现异常的情况
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
System.out.println("减库存后,当前库存" + test1);
return Result.succeed();
}
@Get
@Mapping("test2")
@ApiOperation(value = "第2个测试方法")
public Result<?> test2() throws InterruptedException {
// 获取锁
RLock lock = redissonClient.getLock("testTryLock");
/**
* lock.tryLock
* 第一个参数代表锁的等待时间,如果在30s内还没有释放锁,则会返回false
* 第二个参数代表锁的过期时间
* 第三个参数代表时间单位
*/
if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
if (test2 > 0) {
test2--;
}
//如果该线程还持有该锁,那么释放该锁。如果该线程不持有该锁,说明该线程的锁已到过期时间,自动释放锁 解决空白出现异常的情况
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
System.out.println("====tryLock===减完库存后,当前库存===" + test2);
} else {
return Result.failure("操作繁忙,请稍后重试!");
}
return Result.succeed();
}
@Get
@Mapping("test3")
@ApiOperation(value = "第3个测试方法")
@RedissonLock("test3Lock")
public Result<String> test3() {
if (test3 > 0) {
test3--;
}
System.out.println("===注解模式=== 减完库存后,当前库存===" + test3);
return Result.succeed();
}
}
5.注解及实现
5.1注解
package com.superb.annotation;
import org.noear.solon.annotation.Around;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
/**
* 方法注解
* 设置注解处理器,当方法出现该注解时,处理类为RedissonLockHandler
* Around环绕通知:AOP切面,方法开始时织入分布式锁,方法结束后释放锁
* @Author: ajie
* @CreateTime: 2024-08-01 17:06
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Around(RedissonLockHandler.class)
public @interface RedissonLock {
/**
* 锁名称-redis存入key
* @return
*/
String value();
/**
* 锁存在的时间
* @return
*/
long time() default 30;
/**
* 时间单位,默认秒
*
* @return
*/
TimeUnit unit() default TimeUnit.SECONDS;
}
5.2注解实现
package com.superb.annotation;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.aspect.Interceptor;
import org.noear.solon.core.aspect.Invocation;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
/**
* @Author: ajie
* @CreateTime: 2024-08-01 17:24
*/
@Slf4j
public class RedissonLockHandler implements Interceptor {
@Inject
private RedissonClient redissonClient;
@Override
public Object doIntercept(Invocation inv) throws Throwable {
log.debug("方法开始:获取分布式锁");
RedissonLock annotation = inv.getMethodAnnotation(RedissonLock.class);
RLock lock = redissonClient.getLock(annotation.value());
log.debug("开始加锁:{}", annotation.value());
lock.lock(annotation.time(), annotation.unit());
// 执行目标方法
Object invoke = inv.invoke();
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
log.debug("方法执行完毕,释放锁");
return invoke;
}
}