- 一个简单的(基于redisson的)分布式同步工具类封装
- 背景说明
- 准备工作
- 第一步:引入redisson依赖
- 第二步:配置RedissonClient
- 工具类
- 工具类接口
- 工具类接口的默认实现
- 工具类接口涉及到的两个其它接口
- 使用示例
有些分布式同步逻辑不需要作用于整个方法,只需要作用于指定的业务逻辑代码块即可,类似于synchronized代码块。于是有了下面这个简单的封装类。
准备工作第一步:引入redisson依赖提示:此同步工具类中的redis分布式锁直接采用redisson实现。
第二步:配置RedissonClientorg.redisson redisson 3.17.0
提示:这里的配置以单体redis为例,更多配置详见redisson官网。
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Slf4j
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
String address = host + ":" + port;
log.info("redis address -> {}", address);
config.useSingleServer()
.setAddress("redis://" + address);
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
工具类
工具类接口
import lombok.Getter;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
public interface RedisLockSupport {
R exec(Function
function, P param) throws NotAcquiredRedisLockException;
R exec(NoArgFunction function) throws NotAcquiredRedisLockException;
void voidExec(Consumer
consumer, P param) throws NotAcquiredRedisLockException;
void voidExec(NoArgConsumer consumer) throws NotAcquiredRedisLockException;
@Getter
class NotAcquiredRedisLockException extends RuntimeException{
private final String lockKey;
private final long waitTime;
private final TimeUnit timeUnit;
public NotAcquiredRedisLockException(String lockKey, long waitTime, TimeUnit timeUnit) {
super(String.format("lockKey=%s, waitTime=%d, timeUnit=%d", lockKey, waitTime, timeUnit));
this.lockKey = lockKey;
this.waitTime = waitTime;
this.timeUnit = timeUnit;
}
}
}
工具类接口的默认实现
import lombok.Getter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
@Getter
public class DefaultRedisLockSupport implements RedisLockSupport {
private static volatile RedissonClient defaultRedissonClient;
protected RedissonClient redissonClient;
protected final String lockKey;
protected long waitTime = 1L;
protected long leaseTime = 3L;
protected TimeUnit unit = TimeUnit.SECONDS;
public DefaultRedisLockSupport(String lockKey) {
this.lockKey = lockKey;
}
public DefaultRedisLockSupport(RedissonClient redissonClient, String lockKey) {
this.redissonClient = redissonClient;
this.lockKey = lockKey;
}
public DefaultRedisLockSupport(String lockKey, long waitTime, long leaseTime) {
this.lockKey = lockKey;
this.waitTime = waitTime;
this.leaseTime = leaseTime;
}
public DefaultRedisLockSupport(RedissonClient redissonClient, String lockKey, long waitTime, long leaseTime) {
this.redissonClient = redissonClient;
this.lockKey = lockKey;
this.waitTime = waitTime;
this.leaseTime = leaseTime;
}
public DefaultRedisLockSupport(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
this.lockKey = lockKey;
this.waitTime = waitTime;
this.leaseTime = leaseTime;
this.unit = unit;
}
public DefaultRedisLockSupport(RedissonClient redissonClient, String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
this.redissonClient = redissonClient;
this.lockKey = lockKey;
this.waitTime = waitTime;
this.leaseTime = leaseTime;
this.unit = unit;
}
@Override
public R exec(Function
function, P param) throws NotAcquiredRedisLockException {
RedissonClient client = redissonClient();
RLock lock = client.getLock(lockKey);
boolean obtainLock = false;
try {
obtainLock = lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
// ignore
}
if (obtainLock) {
try {
return function.apply(param);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
throw new NotAcquiredRedisLockException(lockKey, waitTime, unit);
}
@Override
public R exec(NoArgFunction function) throws NotAcquiredRedisLockException {
RedissonClient client = redissonClient();
RLock lock = client.getLock(lockKey);
boolean obtainLock = false;
try {
obtainLock = lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
// ignore
}
if (obtainLock) {
try {
return function.apply();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
throw new NotAcquiredRedisLockException(lockKey, waitTime, unit);
}
@Override
public void voidExec(Consumer
consumer, P param) throws NotAcquiredRedisLockException {
RedissonClient client = redissonClient();
RLock lock = client.getLock(lockKey);
boolean obtainLock = false;
try {
obtainLock = lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
// ignore
}
if (obtainLock) {
try {
consumer.accept(param);
return;
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
throw new NotAcquiredRedisLockException(lockKey, waitTime, unit);
}
@Override
public void voidExec(NoArgConsumer consumer) throws NotAcquiredRedisLockException {
RedissonClient client = redissonClient();
RLock lock = client.getLock(lockKey);
boolean obtainLock = false;
try {
obtainLock = lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
// ignore
}
if (obtainLock) {
try {
consumer.accept();
return;
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
throw new NotAcquiredRedisLockException(lockKey, waitTime, unit);
}
protected RedissonClient redissonClient() {
if (this.redissonClient != null) {
return this.redissonClient;
}
if (DefaultRedisLockSupport.defaultRedissonClient != null) {
return DefaultRedisLockSupport.defaultRedissonClient;
}
throw new IllegalStateException("There is not redissonClient available.");
}
public static void initDefaultRedissonClient(RedissonClient redissonClient) {
if (DefaultRedisLockSupport.defaultRedissonClient != null && !DefaultRedisLockSupport.defaultRedissonClient.equals(redissonClient)) {
throw new IllegalStateException("defaultRedissonClient already been initialized.");
}
synchronized (DefaultRedisLockSupport.class) {
if (DefaultRedisLockSupport.defaultRedissonClient != null) {
if (DefaultRedisLockSupport.defaultRedissonClient.equals(redissonClient)) {
return;
}
throw new IllegalStateException("defaultRedissonClient already been initialized.");
}
DefaultRedisLockSupport.defaultRedissonClient = redissonClient;
}
}
}
工具类接口涉及到的两个其它接口
-
NoArgConsumer
@FunctionalInterface public interface NoArgConsumer { void accept(); } -
NoArgFunction
@FunctionalInterface public interface NoArgFunction
{ R apply(); }
import com.ideaaedi.heywebuy.srv.config.redisson.DefaultRedisLockSupport;
import com.ideaaedi.heywebuy.srv.config.redisson.NoArgConsumer;
import com.ideaaedi.heywebuy.srv.config.redisson.NoArgFunction;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.redisson.api.RedissonClient;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
@Slf4j
@SpringBootTest
public class RedisLockSupportTest {
@Resource
private RedissonClient redissonClient;
@BeforeEach
void initMethod() {
// 在项目启动时注入
DefaultRedisLockSupport.initDefaultRedissonClient(redissonClient);
}
@Test
void test() {
// 无参数 无返回值 NoArgConsumer
new DefaultRedisLockSupport("DefaultRedisLockSupport1", 1, 120).voidExec(new NoArgConsumer() {
@Override
public void accept() {
// 我是业务逻辑
System.out.println("[无参数 无返回值 NoArgConsumer]:ttttt" + 111111);
}
});
// 有参数 无返回值 Consumer
new DefaultRedisLockSupport("DefaultRedisLockSupport1", 1, 120).voidExec(new Consumer() {
@Override
public void accept(Integer s) {
// 我是业务逻辑
System.out.println("[有参数 无返回值 Consumer]:ttttt" + s);
}
}, 2222);
// 无参数 有返回值 NoArgFunction
Map result = new DefaultRedisLockSupport("DefaultRedisLockSupport1", 1, 120)
.exec(new NoArgFunction
相关资料
- 本文已被收录进《程序员成长笔记》 ,笔者JustryDeng



