单元测试添加锁.

This commit is contained in:
lijiahang
2024-05-16 13:36:57 +08:00
parent 77cf635eea
commit 9a7437e8db
19 changed files with 122 additions and 51 deletions

View File

@@ -0,0 +1,33 @@
package com.orion.visor.framework.common.lock;
import java.util.function.Supplier;
/**
* 分布式锁
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/5/16 12:24
*/
public interface Locker {
/**
* 尝试获取锁
*
* @param key key
* @param run run
* @return 是否获取到锁
*/
boolean tryLock(String key, Runnable run);
/**
* 尝试获取锁
*
* @param key key
* @param call call
* @param <T> T
* @return 执行结果
*/
<T> T tryLock(String key, Supplier<T> call);
}

View File

@@ -1,24 +1,24 @@
package com.orion.visor.framework.redis.core.utils; package com.orion.visor.framework.common.utils;
import com.orion.lang.utils.Exceptions; import com.orion.lang.utils.Exceptions;
import com.orion.visor.framework.redis.core.lock.RedisLocker; import com.orion.visor.framework.common.lock.Locker;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* redis 分布式锁工具类 * 分布式锁工具类
* *
* @author Jiahang Li * @author Jiahang Li
* @version 1.0.0 * @version 1.0.0
* @since 2024/4/25 16:42 * @since 2024/4/25 16:42
*/ */
@Slf4j @Slf4j
public class RedisLocks { public class LockerUtils {
private static RedisLocker redisLocker; private static Locker delegate;
private RedisLocks() { private LockerUtils() {
} }
/** /**
@@ -29,7 +29,7 @@ public class RedisLocks {
* @return 是否获取到锁 * @return 是否获取到锁
*/ */
public static boolean tryLock(String key, Runnable run) { public static boolean tryLock(String key, Runnable run) {
return redisLocker.tryLock(key, run); return delegate.tryLock(key, run);
} }
/** /**
@@ -41,15 +41,15 @@ public class RedisLocks {
* @return 执行结果 * @return 执行结果
*/ */
public static <T> T tryLock(String key, Supplier<T> call) { public static <T> T tryLock(String key, Supplier<T> call) {
return redisLocker.tryLock(key, call); return delegate.tryLock(key, call);
} }
public static void setRedisLocker(RedisLocker redisLocker) { public static void setDelegate(Locker delegate) {
if (RedisLocks.redisLocker != null) { if (LockerUtils.delegate != null) {
// unmodified // unmodified
throw Exceptions.state(); throw Exceptions.state();
} }
RedisLocks.redisLocker = redisLocker; LockerUtils.delegate = delegate;
} }
} }

View File

@@ -2,9 +2,12 @@ package ${currentPackage};
import com.orion.lang.define.cache.key.model.LongCacheIdModel; import com.orion.lang.define.cache.key.model.LongCacheIdModel;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable; import lombok.AllArgsConstructor;
import lombok.*; import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.*; import java.util.*;
import java.math.*; import java.math.*;

View File

@@ -1,7 +1,10 @@
package ${currentPackage}; package ${currentPackage};
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable; import java.io.Serializable;
import java.util.*; import java.util.*;

View File

@@ -1,9 +1,12 @@
package ${currentPackage}; package ${currentPackage};
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable; import lombok.AllArgsConstructor;
import lombok.*; import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.*; import java.util.*;
import java.math.*; import java.math.*;

View File

@@ -60,7 +60,7 @@
#if(${dictMap.containsKey(${field.propertyName})}) #if(${dictMap.containsKey(${field.propertyName})})
<!-- $field.comment --> <!-- $field.comment -->
<template #${field.propertyName}="{ record }"> <template #${field.propertyName}="{ record }">
{{ getDictValue($dictMap.get(${field.propertyName}).keyField, record.${field.propertyName}}) }} {{ getDictValue($dictMap.get(${field.propertyName}).keyField, record.${field.propertyName}) }}
</template> </template>
#end #end
#end #end

View File

@@ -1,14 +1,16 @@
package com.orion.visor.framework.redis.configuration; package com.orion.visor.framework.redis.configuration;
import com.orion.visor.framework.common.constant.AutoConfigureOrderConst; import com.orion.visor.framework.common.constant.AutoConfigureOrderConst;
import com.orion.visor.framework.common.lock.Locker;
import com.orion.visor.framework.common.utils.LockerUtils;
import com.orion.visor.framework.redis.configuration.config.RedissonConfig; import com.orion.visor.framework.redis.configuration.config.RedissonConfig;
import com.orion.visor.framework.redis.core.lock.RedisLocker; import com.orion.visor.framework.redis.core.lock.RedisLocker;
import com.orion.visor.framework.redis.core.utils.RedisLocks;
import com.orion.visor.framework.redis.core.utils.RedisUtils; import com.orion.visor.framework.redis.core.utils.RedisUtils;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@@ -23,7 +25,7 @@ import org.springframework.data.redis.serializer.RedisSerializer;
* @version 1.0.0 * @version 1.0.0
* @since 2023/6/28 14:44 * @since 2023/6/28 14:44
*/ */
@Lazy(value = false) @Lazy(false)
@AutoConfiguration @AutoConfiguration
@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_REDIS) @AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_REDIS)
@EnableConfigurationProperties(RedissonConfig.class) @EnableConfigurationProperties(RedissonConfig.class)
@@ -64,9 +66,10 @@ public class OrionRedisAutoConfiguration {
* @return redis 分布式锁 * @return redis 分布式锁
*/ */
@Bean @Bean
public RedisLocker redisLocker(RedissonClient redissonClient) { @ConditionalOnMissingBean
public Locker redisLocker(RedissonClient redissonClient) {
RedisLocker redisLocker = new RedisLocker(redissonClient); RedisLocker redisLocker = new RedisLocker(redissonClient);
RedisLocks.setRedisLocker(redisLocker); LockerUtils.setDelegate(redisLocker);
return redisLocker; return redisLocker;
} }

View File

@@ -24,4 +24,9 @@ public class RedissonConfig {
*/ */
private Integer nettyThreads; private Integer nettyThreads;
public RedissonConfig() {
this.threads = 16;
this.nettyThreads = 16;
}
} }

View File

@@ -1,6 +1,7 @@
package com.orion.visor.framework.redis.core.lock; package com.orion.visor.framework.redis.core.lock;
import com.orion.lang.utils.Exceptions; import com.orion.lang.utils.Exceptions;
import com.orion.visor.framework.common.lock.Locker;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock; import org.redisson.api.RLock;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
@@ -15,7 +16,7 @@ import java.util.function.Supplier;
* @since 2024/4/25 16:42 * @since 2024/4/25 16:42
*/ */
@Slf4j @Slf4j
public class RedisLocker { public class RedisLocker implements Locker {
private final RedissonClient redissonClient; private final RedissonClient redissonClient;
@@ -23,19 +24,13 @@ public class RedisLocker {
this.redissonClient = redissonClient; this.redissonClient = redissonClient;
} }
/** @Override
* 尝试获取锁
*
* @param key key
* @param run run
* @return 是否获取到锁
*/
public boolean tryLock(String key, Runnable run) { public boolean tryLock(String key, Runnable run) {
// 获取锁 // 获取锁
RLock lock = redissonClient.getLock(key); RLock lock = redissonClient.getLock(key);
// 未获取到直接返回 // 未获取到直接返回
if (!lock.tryLock()) { if (!lock.tryLock()) {
log.info("RedisLocks.tryLock failed {}", key); log.info("RedisLocker.tryLock failed {}", key);
return false; return false;
} }
// 执行 // 执行
@@ -47,20 +42,13 @@ public class RedisLocker {
return true; return true;
} }
/** @Override
* 尝试获取锁
*
* @param key key
* @param call call
* @param <T> T
* @return 执行结果
*/
public <T> T tryLock(String key, Supplier<T> call) { public <T> T tryLock(String key, Supplier<T> call) {
// 获取锁 // 获取锁
RLock lock = redissonClient.getLock(key); RLock lock = redissonClient.getLock(key);
// 未获取到直接返回 // 未获取到直接返回
if (!lock.tryLock()) { if (!lock.tryLock()) {
log.info("RedisLocks.tryLock failed {}", key); log.info("RedisLocker.tryLock failed {}", key);
throw Exceptions.lock(); throw Exceptions.lock();
} }
// 执行 // 执行

View File

@@ -10,12 +10,14 @@
{ {
"name": "spring.redisson.threads", "name": "spring.redisson.threads",
"type": "java.lang.Integer", "type": "java.lang.Integer",
"description": "任务线程数." "description": "任务线程数.",
"defaultValue": "16"
}, },
{ {
"name": "spring.redisson.netty-threads", "name": "spring.redisson.netty-threads",
"type": "java.lang.Integer", "type": "java.lang.Integer",
"description": "netty 线程数." "description": "netty 线程数.",
"defaultValue": "16"
} }
] ]
} }

View File

@@ -22,8 +22,8 @@ import javax.sql.DataSource;
* @version 1.0.0 * @version 1.0.0
* @since 2023/8/23 17:17 * @since 2023/8/23 17:17
*/ */
@Lazy(false)
@Profile("unit-test") @Profile("unit-test")
@Lazy(value = false)
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class) @ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class)
@ConditionalOnSingleCandidate(DataSource.class) @ConditionalOnSingleCandidate(DataSource.class)

View File

@@ -1,6 +1,8 @@
package com.orion.visor.framework.test.configuration; package com.orion.visor.framework.test.configuration;
import com.github.fppt.jedismock.RedisServer; import com.github.fppt.jedismock.RedisServer;
import com.orion.visor.framework.common.lock.Locker;
import com.orion.visor.framework.common.utils.LockerUtils;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@@ -8,6 +10,8 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.Profile;
import java.util.function.Supplier;
/** /**
* 单元测试 redis mock server 初始化 * 单元测试 redis mock server 初始化
* *
@@ -34,4 +38,25 @@ public class OrionMockRedisTestConfiguration {
return server; return server;
} }
/**
* @return 单元测试分布式锁
*/
@Bean
public Locker unitTestLocker() {
Locker locker = new Locker() {
@Override
public boolean tryLock(String key, Runnable run) {
run.run();
return true;
}
@Override
public <T> T tryLock(String key, Supplier<T> call) {
return call.get();
}
};
LockerUtils.setDelegate(locker);
return locker;
}
} }

View File

@@ -1,6 +1,6 @@
package com.orion.visor.module.asset.task; package com.orion.visor.module.asset.task;
import com.orion.visor.framework.redis.core.utils.RedisLocks; import com.orion.visor.framework.common.utils.LockerUtils;
import com.orion.visor.module.asset.service.CommandSnippetGroupService; import com.orion.visor.module.asset.service.CommandSnippetGroupService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
@@ -34,7 +34,7 @@ public class CommandSnippetGroupAutoClearTask {
public void clear() { public void clear() {
log.info("CommandSnippetGroupAutoClearTask.clear start"); log.info("CommandSnippetGroupAutoClearTask.clear start");
// 获取锁并清理 // 获取锁并清理
RedisLocks.tryLock(LOCK_KEY, commandSnippetGroupService::clearUnusedGroup); LockerUtils.tryLock(LOCK_KEY, commandSnippetGroupService::clearUnusedGroup);
log.info("CommandSnippetGroupAutoClearTask.clear finish"); log.info("CommandSnippetGroupAutoClearTask.clear finish");
} }

View File

@@ -4,7 +4,7 @@ import com.orion.lang.utils.Strings;
import com.orion.lang.utils.io.Files1; import com.orion.lang.utils.io.Files1;
import com.orion.lang.utils.time.Dates; import com.orion.lang.utils.time.Dates;
import com.orion.visor.framework.common.file.FileClient; import com.orion.visor.framework.common.file.FileClient;
import com.orion.visor.framework.redis.core.utils.RedisLocks; import com.orion.visor.framework.common.utils.LockerUtils;
import com.orion.visor.module.asset.dao.ExecHostLogDAO; import com.orion.visor.module.asset.dao.ExecHostLogDAO;
import com.orion.visor.module.asset.define.config.AppExecLogConfig; import com.orion.visor.module.asset.define.config.AppExecLogConfig;
import com.orion.visor.module.asset.entity.domain.ExecHostLogDO; import com.orion.visor.module.asset.entity.domain.ExecHostLogDO;
@@ -50,7 +50,7 @@ public class ExecLogFileAutoClearTask {
public void clear() { public void clear() {
log.info("ExecLogFileAutoClearTask.clear start"); log.info("ExecLogFileAutoClearTask.clear start");
// 获取锁并且执行 // 获取锁并且执行
RedisLocks.tryLock(LOCK_KEY, this::doClearFile); LockerUtils.tryLock(LOCK_KEY, this::doClearFile);
log.info("ExecLogFileAutoClearTask.clear finish"); log.info("ExecLogFileAutoClearTask.clear finish");
} }

View File

@@ -1,6 +1,6 @@
package com.orion.visor.module.asset.task; package com.orion.visor.module.asset.task;
import com.orion.visor.framework.redis.core.utils.RedisLocks; import com.orion.visor.framework.common.utils.LockerUtils;
import com.orion.visor.module.asset.service.PathBookmarkGroupService; import com.orion.visor.module.asset.service.PathBookmarkGroupService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
@@ -34,7 +34,7 @@ public class PathBookmarkGroupAutoClearTask {
public void clear() { public void clear() {
log.info("PathBookmarkGroupAutoClearTask.clear start"); log.info("PathBookmarkGroupAutoClearTask.clear start");
// 获取锁并清理 // 获取锁并清理
RedisLocks.tryLock(LOCK_KEY, pathBookmarkGroupService::clearUnusedGroup); LockerUtils.tryLock(LOCK_KEY, pathBookmarkGroupService::clearUnusedGroup);
log.info("PathBookmarkGroupAutoClearTask.clear finish"); log.info("PathBookmarkGroupAutoClearTask.clear finish");
} }

View File

@@ -21,6 +21,9 @@ spring:
host: 127.0.0.1 host: 127.0.0.1
port: 16379 port: 16379
database: 0 database: 0
redisson:
threads: 2
netty-threads: 2
mybatis-plus: mybatis-plus:
lazy-initialization: true lazy-initialization: true

View File

@@ -1,6 +1,6 @@
package com.orion.visor.module.infra.task; package com.orion.visor.module.infra.task;
import com.orion.visor.framework.redis.core.utils.RedisLocks; import com.orion.visor.framework.common.utils.LockerUtils;
import com.orion.visor.module.infra.service.TagService; import com.orion.visor.module.infra.service.TagService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
@@ -34,7 +34,7 @@ public class TagAutoClearTask {
public void clear() { public void clear() {
log.info("TagAutoClearTask.clear start"); log.info("TagAutoClearTask.clear start");
// 获取锁并清理 // 获取锁并清理
RedisLocks.tryLock(LOCK_KEY, tagService::clearUnusedTag); LockerUtils.tryLock(LOCK_KEY, tagService::clearUnusedTag);
log.info("TagAutoClearTask.clear finish"); log.info("TagAutoClearTask.clear finish");
} }

View File

@@ -21,6 +21,9 @@ spring:
host: 127.0.0.1 host: 127.0.0.1
port: 16379 port: 16379
database: 0 database: 0
redisson:
threads: 2
netty-threads: 2
mybatis-plus: mybatis-plus:
lazy-initialization: true lazy-initialization: true

View File

@@ -69,7 +69,7 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@logo-width: 152px; @logo-width: 148px;
.terminal-header { .terminal-header {
height: 100%; height: 100%;