init version
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4" />
|
||||
38
joju-framework/joju-spring-boot-starter-protection/pom.xml
Normal file
38
joju-framework/joju-spring-boot-starter-protection/pom.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.jojubanking.boot</groupId>
|
||||
<artifactId>joju-framework</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>joju-spring-boot-starter-protection</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>服务保证,提供分布式锁、幂等、限流、熔断等等功能</description>
|
||||
<url>https://www.jojubanking.com</url>
|
||||
|
||||
<dependencies>
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.jojubanking.boot</groupId>
|
||||
<artifactId>joju-spring-boot-starter-redis</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 服务保障相关 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.resilience4j</groupId>
|
||||
<artifactId>resilience4j-spring-boot2</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.jojubanking.boot.framework.idempotent.config;
|
||||
|
||||
import com.jojubanking.boot.framework.idempotent.core.aop.IdempotentAspect;
|
||||
import com.jojubanking.boot.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver;
|
||||
import com.jojubanking.boot.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver;
|
||||
import com.jojubanking.boot.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
||||
import com.jojubanking.boot.framework.idempotent.core.redis.IdempotentRedisDAO;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import com.jojubanking.boot.framework.redis.config.JojuRedisAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@AutoConfigureAfter(JojuRedisAutoConfiguration.class)
|
||||
public class JojuIdempotentConfiguration {
|
||||
|
||||
@Bean
|
||||
public IdempotentAspect idempotentAspect(List<IdempotentKeyResolver> keyResolvers, IdempotentRedisDAO idempotentRedisDAO) {
|
||||
return new IdempotentAspect(keyResolvers, idempotentRedisDAO);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IdempotentRedisDAO idempotentRedisDAO(StringRedisTemplate stringRedisTemplate) {
|
||||
return new IdempotentRedisDAO(stringRedisTemplate);
|
||||
}
|
||||
|
||||
// ========== 各种 IdempotentKeyResolver Bean ==========
|
||||
|
||||
@Bean
|
||||
public DefaultIdempotentKeyResolver defaultIdempotentKeyResolver() {
|
||||
return new DefaultIdempotentKeyResolver();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ExpressionIdempotentKeyResolver expressionIdempotentKeyResolver() {
|
||||
return new ExpressionIdempotentKeyResolver();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.jojubanking.boot.framework.idempotent.core.annotation;
|
||||
|
||||
import com.jojubanking.boot.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver;
|
||||
import com.jojubanking.boot.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
||||
|
||||
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 TW
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Idempotent {
|
||||
|
||||
/**
|
||||
* 幂等的超时时间,默认为 1 秒
|
||||
*
|
||||
* 注意,如果执行时间超过它,请求还是会进来
|
||||
*/
|
||||
int timeout() default 1;
|
||||
/**
|
||||
* 时间单位,默认为 SECONDS 秒
|
||||
*/
|
||||
TimeUnit timeUnit() default TimeUnit.SECONDS;
|
||||
|
||||
/**
|
||||
* 提示信息,正在执行中的提示
|
||||
*/
|
||||
String message() default "重复请求,请稍后重试";
|
||||
|
||||
/**
|
||||
* 使用的 Key 解析器
|
||||
*/
|
||||
Class<? extends IdempotentKeyResolver> keyResolver() default DefaultIdempotentKeyResolver.class;
|
||||
/**
|
||||
* 使用的 Key 参数
|
||||
*/
|
||||
String keyArg() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.jojubanking.boot.framework.idempotent.core.aop;
|
||||
|
||||
import com.jojubanking.boot.framework.common.exception.ServiceException;
|
||||
import com.jojubanking.boot.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import com.jojubanking.boot.framework.idempotent.core.annotation.Idempotent;
|
||||
import com.jojubanking.boot.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
||||
import com.jojubanking.boot.framework.idempotent.core.redis.IdempotentRedisDAO;
|
||||
import com.jojubanking.boot.framework.common.util.collection.CollectionUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 拦截声明了 {@link Idempotent} 注解的方法,实现幂等操作
|
||||
*
|
||||
* @author TW
|
||||
*/
|
||||
@Aspect
|
||||
@Slf4j
|
||||
public class IdempotentAspect {
|
||||
|
||||
/**
|
||||
* IdempotentKeyResolver 集合
|
||||
*/
|
||||
private final Map<Class<? extends IdempotentKeyResolver>, IdempotentKeyResolver> keyResolvers;
|
||||
|
||||
private final IdempotentRedisDAO idempotentRedisDAO;
|
||||
|
||||
public IdempotentAspect(List<IdempotentKeyResolver> keyResolvers, IdempotentRedisDAO idempotentRedisDAO) {
|
||||
this.keyResolvers = CollectionUtils.convertMap(keyResolvers, IdempotentKeyResolver::getClass);
|
||||
this.idempotentRedisDAO = idempotentRedisDAO;
|
||||
}
|
||||
|
||||
@Before("@annotation(idempotent)")
|
||||
public void beforePointCut(JoinPoint joinPoint, Idempotent idempotent) {
|
||||
// 获得 IdempotentKeyResolver
|
||||
IdempotentKeyResolver keyResolver = keyResolvers.get(idempotent.keyResolver());
|
||||
Assert.notNull(keyResolver, "找不到对应的 IdempotentKeyResolver");
|
||||
// 解析 Key
|
||||
String key = keyResolver.resolver(joinPoint, idempotent);
|
||||
|
||||
// 锁定 Key。
|
||||
boolean success = idempotentRedisDAO.setIfAbsent(key, idempotent.timeout(), idempotent.timeUnit());
|
||||
// 锁定失败,抛出异常
|
||||
if (!success) {
|
||||
log.info("[beforePointCut][方法({}) 参数({}) 存在重复请求]", joinPoint.getSignature().toString(), joinPoint.getArgs());
|
||||
throw new ServiceException(GlobalErrorCodeConstants.REPEATED_REQUESTS.getCode(), idempotent.message());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.jojubanking.boot.framework.idempotent.core.keyresolver;
|
||||
|
||||
import com.jojubanking.boot.framework.idempotent.core.annotation.Idempotent;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
|
||||
/**
|
||||
* 幂等 Key 解析器接口
|
||||
*
|
||||
* @author TW
|
||||
*/
|
||||
public interface IdempotentKeyResolver {
|
||||
|
||||
/**
|
||||
* 解析一个 Key
|
||||
*
|
||||
* @param idempotent 幂等注解
|
||||
* @param joinPoint AOP 切面
|
||||
* @return Key
|
||||
*/
|
||||
String resolver(JoinPoint joinPoint, Idempotent idempotent);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.jojubanking.boot.framework.idempotent.core.keyresolver.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.jojubanking.boot.framework.idempotent.core.annotation.Idempotent;
|
||||
import com.jojubanking.boot.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
|
||||
/**
|
||||
* 默认幂等 Key 解析器,使用方法名 + 方法参数,组装成一个 Key
|
||||
*
|
||||
* 为了避免 Key 过长,使用 MD5 进行“压缩”
|
||||
*
|
||||
* @author TW
|
||||
*/
|
||||
public class DefaultIdempotentKeyResolver implements IdempotentKeyResolver {
|
||||
|
||||
@Override
|
||||
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
||||
String methodName = joinPoint.getSignature().toString();
|
||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
||||
return SecureUtil.md5(methodName + argsStr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.jojubanking.boot.framework.idempotent.core.keyresolver.impl;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.jojubanking.boot.framework.idempotent.core.annotation.Idempotent;
|
||||
import com.jojubanking.boot.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 基于 Spring EL 表达式,
|
||||
*
|
||||
* @author TW
|
||||
*/
|
||||
public class ExpressionIdempotentKeyResolver implements IdempotentKeyResolver {
|
||||
|
||||
private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
private final ExpressionParser expressionParser = new SpelExpressionParser();
|
||||
|
||||
@Override
|
||||
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
||||
// 获得被拦截方法参数名列表
|
||||
Method method = getMethod(joinPoint);
|
||||
Object[] args = joinPoint.getArgs();
|
||||
String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method);
|
||||
// 准备 Spring EL 表达式解析的上下文
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
if (ArrayUtil.isNotEmpty(parameterNames)) {
|
||||
for (int i = 0; i < parameterNames.length; i++) {
|
||||
evaluationContext.setVariable(parameterNames[i], args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 解析参数
|
||||
Expression expression = expressionParser.parseExpression(idempotent.keyArg());
|
||||
return expression.getValue(evaluationContext, String.class);
|
||||
}
|
||||
|
||||
private static Method getMethod(JoinPoint point) {
|
||||
// 处理,声明在类上的情况
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
if (!method.getDeclaringClass().isInterface()) {
|
||||
return method;
|
||||
}
|
||||
|
||||
// 处理,声明在接口上的情况
|
||||
try {
|
||||
return point.getTarget().getClass().getDeclaredMethod(
|
||||
point.getSignature().getName(), method.getParameterTypes());
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.jojubanking.boot.framework.idempotent.core.redis;
|
||||
|
||||
import com.jojubanking.boot.framework.redis.core.RedisKeyDefine;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.jojubanking.boot.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
|
||||
|
||||
/**
|
||||
* 幂等 Redis DAO
|
||||
*
|
||||
* @author TW
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class IdempotentRedisDAO {
|
||||
|
||||
private static final RedisKeyDefine IDEMPOTENT = new RedisKeyDefine("幂等操作",
|
||||
"idempotent:%s", // 参数为 uuid
|
||||
STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
|
||||
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
||||
public Boolean setIfAbsent(String key, long timeout, TimeUnit timeUnit) {
|
||||
String redisKey = formatKey(key);
|
||||
return redisTemplate.opsForValue().setIfAbsent(redisKey, "", timeout, timeUnit);
|
||||
}
|
||||
|
||||
private static String formatKey(String key) {
|
||||
return String.format(IDEMPOTENT.getKeyTemplate(), key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 幂等组件,参考 https://github.com/it4alla/idempotent 项目实现
|
||||
* 实现原理是,相同参数的方法,一段时间内,有且仅能执行一次。通过这样的方式,保证幂等性。
|
||||
*
|
||||
* 使用场景:例如说,用户快速的双击了某个按钮,前端没有禁用该按钮,导致发送了两次重复的请求。
|
||||
*
|
||||
* 和 it4alla/idempotent 组件的差异点,主要体现在两点:
|
||||
* 1. 我们去掉了 @Idempotent 注解的 delKey 属性。原因是,本质上 delKey 为 true 时,实现的是分布式锁的能力
|
||||
* 此时,我们偏向使用 Lock4j 组件。原则上,一个组件只提供一种单一的能力。
|
||||
* 2. 考虑到组件的通用性,我们并未像 it4alla/idempotent 组件一样使用 Redisson RMap 结构,而是直接使用 Redis 的 String 数据格式。
|
||||
*/
|
||||
package com.jojubanking.boot.framework.idempotent;
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.jojubanking.boot.lock4j.config;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration;
|
||||
import com.jojubanking.boot.lock4j.core.DefaultLockFailureStrategy;
|
||||
import com.jojubanking.boot.lock4j.core.Lock4jRedisKeyConstants;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@AutoConfigureBefore(LockAutoConfiguration.class)
|
||||
public class JojuLock4jConfiguration {
|
||||
|
||||
static {
|
||||
// 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到
|
||||
// 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举
|
||||
ClassUtil.loadClass(Lock4jRedisKeyConstants.class.getName());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultLockFailureStrategy lockFailureStrategy() {
|
||||
return new DefaultLockFailureStrategy();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.jojubanking.boot.lock4j.core;
|
||||
|
||||
import com.jojubanking.boot.framework.common.exception.ServiceException;
|
||||
import com.jojubanking.boot.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import com.baomidou.lock.LockFailureStrategy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 自定义获取锁失败策略,抛出 {@link ServiceException} 异常
|
||||
*/
|
||||
@Slf4j
|
||||
public class DefaultLockFailureStrategy implements LockFailureStrategy {
|
||||
|
||||
@Override
|
||||
public void onLockFailure(String key, long acquireTimeout, int acquireCount) {
|
||||
log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取超时时长:{} ms]", Thread.currentThread().getName(), key, acquireTimeout);
|
||||
throw new ServiceException(GlobalErrorCodeConstants.LOCKED);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.jojubanking.boot.lock4j.core;
|
||||
|
||||
import com.jojubanking.boot.framework.redis.core.RedisKeyDefine;
|
||||
import org.redisson.api.RLock;
|
||||
|
||||
import static com.jojubanking.boot.framework.redis.core.RedisKeyDefine.KeyTypeEnum.HASH;
|
||||
|
||||
/**
|
||||
* Lock4j Redis Key 枚举类
|
||||
*
|
||||
* @author TW
|
||||
*/
|
||||
public interface Lock4jRedisKeyConstants {
|
||||
|
||||
RedisKeyDefine LOCK4J = new RedisKeyDefine("分布式锁",
|
||||
"lock4j:%s", // 参数来自 DefaultLockKeyBuilder 类
|
||||
HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 分布式锁组件,使用 https://gitee.com/baomidou/lock4j 开源项目
|
||||
*/
|
||||
package com.jojubanking.boot.lock4j;
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 使用 Resilience4j 组件,实现服务保障,包括:
|
||||
* 1. 熔断器
|
||||
* 2. 限流器
|
||||
* 3. 舱壁隔离
|
||||
* 4. 重试
|
||||
* 5. 限时器
|
||||
*/
|
||||
package com.jojubanking.boot.resilience4j;
|
||||
@@ -0,0 +1 @@
|
||||
<https://www.iocoder.cn/Spring-Boot/Resilience4j/?joju>
|
||||
@@ -0,0 +1,3 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.jojubanking.boot.framework.idempotent.config.JojuIdempotentConfiguration,\
|
||||
com.jojubanking.boot.lock4j.config.JojuLock4jConfiguration
|
||||
@@ -0,0 +1,3 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.jojubanking.boot.framework.idempotent.config.JojuIdempotentConfiguration,\
|
||||
com.jojubanking.boot.lock4j.config.JojuLock4jConfiguration
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
#Generated by Maven
|
||||
#Wed Apr 02 13:07:26 CST 2025
|
||||
version=2.0.0-beta
|
||||
groupId=com.jojubanking.boot
|
||||
artifactId=joju-spring-boot-starter-protection
|
||||
@@ -0,0 +1,10 @@
|
||||
com\jojubanking\boot\framework\idempotent\core\keyresolver\impl\DefaultIdempotentKeyResolver.class
|
||||
com\jojubanking\boot\framework\idempotent\core\keyresolver\impl\ExpressionIdempotentKeyResolver.class
|
||||
com\jojubanking\boot\framework\idempotent\config\JojuIdempotentConfiguration.class
|
||||
com\jojubanking\boot\framework\idempotent\core\annotation\Idempotent.class
|
||||
com\jojubanking\boot\framework\idempotent\core\keyresolver\IdempotentKeyResolver.class
|
||||
com\jojubanking\boot\framework\idempotent\core\redis\IdempotentRedisDAO.class
|
||||
com\jojubanking\boot\framework\idempotent\core\aop\IdempotentAspect.class
|
||||
com\jojubanking\boot\lock4j\core\DefaultLockFailureStrategy.class
|
||||
com\jojubanking\boot\lock4j\config\JojuLock4jConfiguration.class
|
||||
com\jojubanking\boot\lock4j\core\Lock4jRedisKeyConstants.class
|
||||
@@ -0,0 +1,13 @@
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\framework\idempotent\package-info.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\framework\idempotent\core\redis\IdempotentRedisDAO.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\framework\idempotent\config\JojuIdempotentConfiguration.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\framework\idempotent\core\keyresolver\impl\DefaultIdempotentKeyResolver.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\lock4j\package-info.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\framework\idempotent\core\aop\IdempotentAspect.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\framework\idempotent\core\keyresolver\impl\ExpressionIdempotentKeyResolver.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\framework\idempotent\core\keyresolver\IdempotentKeyResolver.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\framework\idempotent\core\annotation\Idempotent.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\lock4j\core\Lock4jRedisKeyConstants.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\resilience4j\package-info.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\lock4j\config\JojuLock4jConfiguration.java
|
||||
D:\^新版项目\05.九聚项目\32.库尔勒妇幼二期\下园体检\examination\joju-framework\joju-spring-boot-starter-protection\src\main\java\com\jojubanking\boot\lock4j\core\DefaultLockFailureStrategy.java
|
||||
Reference in New Issue
Block a user