【修改】将jeecg字样修改为jero(修改完毕)

This commit is contained in:
zer0Black
2021-03-11 09:03:44 +08:00
parent ba4ef45423
commit 684543524b
688 changed files with 394236 additions and 13426 deletions
@@ -0,0 +1,58 @@
package com.jero.boot.starter.lock.annotation;
import com.jero.boot.starter.lock.enums.LockModel;
import java.lang.annotation.*;
/**
* Redisson分布式锁注解
*
* @author zyf
* @date 2020-11-11
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DistributedLock {
/**
* 锁的模式:如果不设置,自动模式,当参数只有一个.使用 REENTRANT 参数多个 MULTIPLE
*/
LockModel lockModel() default LockModel.AUTO;
/**
* 如果keys有多个,如果不设置,则使用 联锁
* @return
*/
String[] lockKey() default {};
/**
* key的静态常量:当key的spel的值是LIST,数组时使用+号连接将会被spel认为这个变量是个字符串,只能产生一把锁,达不到我们的目的,<br />
* 而我们如果又需要一个常量的话.这个参数将会在拼接在每个元素的后面
* @return
*/
String keyConstant() default "";
/**
* 锁超时时间,默认30000毫秒
*
* @return int
*/
long expireSeconds() default 30000L;
/**
* 等待加锁超时时间,默认10000毫秒 -1 则表示一直等待
*
* @return int
*/
long waitTime() default 10000L;
/**
* 未取到锁时提示信息
*
* @return
*/
String failMsg() default "获取锁失败,请稍后重试";
}
@@ -0,0 +1,218 @@
package com.jero.boot.starter.lock.aspect;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import com.jero.boot.starter.lock.annotation.DistributedLock;
import com.jero.boot.starter.lock.enums.LockModel;
import org.redisson.RedissonMultiLock;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
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 org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁解析器
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
@Aspect
@Component
public class DistributedLockHandler {
@Autowired(required = false)
private RedissonClient redissonClient;
/**
* 切面环绕通知
*
* @param joinPoint
* @param distributedLock
* @return Object
*/
@SneakyThrows
@Around("@annotation(distributedLock)")
public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
Object obj = null;
log.info("进入RedisLock环绕通知...");
RLock rLock = getLock(joinPoint, distributedLock);
boolean res = false;
//获取超时时间
long expireSeconds = distributedLock.expireSeconds();
//等待多久,n秒内获取不到锁,则直接返回
long waitTime = distributedLock.waitTime();
//执行aop
if (rLock != null) {
try {
if (waitTime == -1) {
res = true;
//一直等待加锁
rLock.lock(expireSeconds, TimeUnit.MILLISECONDS);
} else {
res = rLock.tryLock(waitTime, expireSeconds, TimeUnit.MILLISECONDS);
}
if (res) {
obj = joinPoint.proceed();
} else {
log.error("获取锁异常");
}
} finally {
if (res) {
rLock.unlock();
}
}
}
log.info("结束RedisLock环绕通知...");
return obj;
}
@SneakyThrows
private RLock getLock(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
String[] keys = distributedLock.lockKey();
if (keys.length == 0) {
throw new RuntimeException("keys不能为空");
}
String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(((MethodSignature) joinPoint.getSignature()).getMethod());
Object[] args = joinPoint.getArgs();
LockModel lockModel = distributedLock.lockModel();
if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.REDLOCK) && keys.length > 1) {
throw new RuntimeException("参数有多个,锁模式为->" + lockModel.name() + ".无法锁定");
}
RLock rLock = null;
String keyConstant = distributedLock.keyConstant();
if (lockModel.equals(LockModel.AUTO)) {
if (keys.length > 1) {
lockModel = LockModel.REDLOCK;
} else {
lockModel = LockModel.REENTRANT;
}
}
switch (lockModel) {
case FAIR:
rLock = redissonClient.getFairLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0));
break;
case REDLOCK:
List<RLock> rLocks = new ArrayList<>();
for (String key : keys) {
List<String> valueBySpEL = getValueBySpEL(key, parameterNames, args, keyConstant);
for (String s : valueBySpEL) {
rLocks.add(redissonClient.getLock(s));
}
}
RLock[] locks = new RLock[rLocks.size()];
int index = 0;
for (RLock r : rLocks) {
locks[index++] = r;
}
rLock = new RedissonRedLock(locks);
break;
case MULTIPLE:
rLocks = new ArrayList<>();
for (String key : keys) {
List<String> valueBySpEL = getValueBySpEL(key, parameterNames, args, keyConstant);
for (String s : valueBySpEL) {
rLocks.add(redissonClient.getLock(s));
}
}
locks = new RLock[rLocks.size()];
index = 0;
for (RLock r : rLocks) {
locks[index++] = r;
}
rLock = new RedissonMultiLock(locks);
break;
case REENTRANT:
List<String> valueBySpEL = getValueBySpEL(keys[0], parameterNames, args, keyConstant);
//如果spel表达式是数组或者LIST 则使用红锁
if (valueBySpEL.size() == 1) {
rLock = redissonClient.getLock(valueBySpEL.get(0));
} else {
locks = new RLock[valueBySpEL.size()];
index = 0;
for (String s : valueBySpEL) {
locks[index++] = redissonClient.getLock(s);
}
rLock = new RedissonRedLock(locks);
}
break;
case READ:
rLock = redissonClient.getReadWriteLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0)).readLock();
break;
case WRITE:
rLock = redissonClient.getReadWriteLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0)).writeLock();
break;
}
return rLock;
}
/**
* 通过spring SpEL 获取参数
*
* @param key 定义的key值 以#开头 例如:#user
* @param parameterNames 形参
* @param values 形参值
* @param keyConstant key的常亮
* @return
*/
public List<String> getValueBySpEL(String key, String[] parameterNames, Object[] values, String keyConstant) {
List<String> keys = new ArrayList<>();
if (!key.contains("#")) {
String s = "redis:lock:" + key + keyConstant;
log.info("lockKey:" + s);
keys.add(s);
return keys;
}
//spel解析器
ExpressionParser parser = new SpelExpressionParser();
//spel上下文
EvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i], values[i]);
}
Expression expression = parser.parseExpression(key);
Object value = expression.getValue(context);
if (value != null) {
if (value instanceof List) {
List value1 = (List) value;
for (Object o : value1) {
addKeys(keys, o, keyConstant);
}
} else if (value.getClass().isArray()) {
Object[] obj = (Object[]) value;
for (Object o : obj) {
addKeys(keys, o, keyConstant);
}
} else {
addKeys(keys, value, keyConstant);
}
}
log.info("表达式key={},value={}", key, keys);
return keys;
}
private void addKeys(List<String> keys, Object o, String keyConstant) {
keys.add("redis:lock:" + o.toString() + keyConstant);
}
}
@@ -0,0 +1,99 @@
package com.jero.boot.starter.lock.client;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁实现基于Redisson
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
@Component
public class RedissonLockClient {
@Autowired
private RedissonClient redissonClient;
/**
* 获取锁
*/
public RLock getLock(String lockKey) {
return redissonClient.getLock(lockKey);
}
/**
* 加锁操作
*
* @return boolean
*/
public boolean tryLock(String lockName, long expireSeconds) {
return tryLock(lockName, 0, expireSeconds);
}
/**
* 加锁操作
*
* @return boolean
*/
public boolean tryLock(String lockName, long waitTime, long expireSeconds) {
RLock rLock = getLock(lockName);
boolean getLock = false;
try {
getLock = rLock.tryLock(waitTime, expireSeconds, TimeUnit.SECONDS);
if (getLock) {
log.info("获取锁成功,lockName={}", lockName);
} else {
log.info("获取锁失败,lockName={}", lockName);
}
} catch (InterruptedException e) {
log.error("获取式锁异常,lockName=" + lockName, e);
getLock = false;
}
return getLock;
}
/**
* 锁lockKey
*
* @param lockKey
* @return
*/
public RLock lock(String lockKey) {
RLock lock = getLock(lockKey);
lock.lock();
return lock;
}
/**
* 锁lockKey
*
* @param lockKey
* @param leaseTime
* @return
*/
public RLock lock(String lockKey, long leaseTime) {
RLock lock = getLock(lockKey);
lock.lock(leaseTime, TimeUnit.SECONDS);
return lock;
}
/**
* 解锁
*
* @param lockName 锁名称
*/
public void unlock(String lockName) {
redissonClient.getLock(lockName).unlock();
}
}
@@ -0,0 +1,36 @@
package com.jero.boot.starter.lock.config;
import lombok.extern.slf4j.Slf4j;
import com.jero.boot.starter.lock.core.RedissonManager;
import com.jero.boot.starter.lock.prop.RedissonProperties;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Redisson自动化配置
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
@Configuration
@ConditionalOnClass(RedissonProperties.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonConfiguration {
@Bean
@ConditionalOnMissingBean(RedissonClient.class)
public RedissonClient redissonClient(RedissonProperties redissonProperties) {
RedissonManager redissonManager = new RedissonManager(redissonProperties);
log.info("RedissonManager初始化完成,当前连接方式:" + redissonProperties.getType() + ",连接地址:" + redissonProperties.getAddress());
return redissonManager.getRedisson();
}
}
@@ -0,0 +1,100 @@
package com.jero.boot.starter.lock.core;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import com.jero.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import com.jero.boot.starter.lock.prop.RedissonProperties;
import com.jero.boot.starter.lock.core.strategy.impl.ClusterRedissonConfigStrategyImpl;
import com.jero.boot.starter.lock.core.strategy.impl.MasterslaveRedissonConfigStrategyImpl;
import com.jero.boot.starter.lock.core.strategy.impl.SentinelRedissonConfigStrategyImpl;
import com.jero.boot.starter.lock.core.strategy.impl.StandaloneRedissonConfigStrategyImpl;
import com.jero.boot.starter.lock.enums.RedisConnectionType;
import org.redisson.Redisson;
import org.redisson.config.Config;
/**
* Redisson配置管理器,用于初始化的redisson实例
*
* @author zyf
* @date 2020-11-12
*/
@Slf4j
public class RedissonManager {
private Config config = new Config();
private Redisson redisson = null;
public RedissonManager() {
}
public RedissonManager(RedissonProperties redissonProperties) {
//装配开关
Boolean enabled = redissonProperties.getEnabled();
if (enabled) {
try {
config = RedissonConfigFactory.getInstance().createConfig(redissonProperties);
redisson = (Redisson) Redisson.create(config);
} catch (Exception e) {
log.error("Redisson初始化错误", e);
}
}
}
public Redisson getRedisson() {
return redisson;
}
/**
* Redisson连接方式配置工厂
* 双重检查锁
*/
static class RedissonConfigFactory {
private RedissonConfigFactory() {
}
private static volatile RedissonConfigFactory factory = null;
public static RedissonConfigFactory getInstance() {
if (factory == null) {
synchronized (Object.class) {
if (factory == null) {
factory = new RedissonConfigFactory();
}
}
}
return factory;
}
/**
* 根据连接类型創建连接方式的配置
*
* @param redissonProperties
* @return Config
*/
Config createConfig(RedissonProperties redissonProperties) {
Preconditions.checkNotNull(redissonProperties);
Preconditions.checkNotNull(redissonProperties.getAddress(), "redis地址未配置");
RedisConnectionType connectionType = redissonProperties.getType();
// 声明连接方式
RedissonConfigStrategy redissonConfigStrategy;
if (connectionType.equals(RedisConnectionType.SENTINEL)) {
redissonConfigStrategy = new SentinelRedissonConfigStrategyImpl();
} else if (connectionType.equals(RedisConnectionType.CLUSTER)) {
redissonConfigStrategy = new ClusterRedissonConfigStrategyImpl();
} else if (connectionType.equals(RedisConnectionType.MASTERSLAVE)) {
redissonConfigStrategy = new MasterslaveRedissonConfigStrategyImpl();
} else {
redissonConfigStrategy = new StandaloneRedissonConfigStrategyImpl();
}
Preconditions.checkNotNull(redissonConfigStrategy, "连接方式创建异常");
return redissonConfigStrategy.createRedissonConfig(redissonProperties);
}
}
}
@@ -0,0 +1,21 @@
package com.jero.boot.starter.lock.core.strategy;
import com.jero.boot.starter.lock.prop.RedissonProperties;
import org.redisson.config.Config;
/**
* Redisson配置构建接口
*
* @author zyf
* @date 2020-11-11
*/
public interface RedissonConfigStrategy {
/**
* 根据不同的Redis配置策略创建对应的Config
*
* @param redissonProperties
* @return Config
*/
Config createRedissonConfig(RedissonProperties redissonProperties);
}
@@ -0,0 +1,43 @@
package com.jero.boot.starter.lock.core.strategy.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.jero.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import com.jero.boot.starter.lock.prop.RedissonProperties;
import com.jero.boot.starter.lock.enums.GlobalConstant;
import org.redisson.config.Config;
/**
* 集群方式Redisson配置
* cluster方式至少6个节点(3主3从)
* 配置方式:127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
public class ClusterRedissonConfigStrategyImpl implements RedissonConfigStrategy {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
String[] addrTokens = address.split(",");
// 设置集群(cluster)节点的服务IP和端口
for (int i = 0; i < addrTokens.length; i++) {
config.useClusterServers().addNodeAddress(GlobalConstant.REDIS_CONNECTION_PREFIX + addrTokens[i]);
if (StringUtils.isNotBlank(password)) {
config.useClusterServers().setPassword(password);
}
}
log.info("初始化集群方式Config,连接地址:" + address);
} catch (Exception e) {
log.error("集群Redisson初始化错误", e);
e.printStackTrace();
}
return config;
}
}
@@ -0,0 +1,54 @@
package com.jero.boot.starter.lock.core.strategy.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.jero.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import com.jero.boot.starter.lock.prop.RedissonProperties;
import com.jero.boot.starter.lock.enums.GlobalConstant;
import org.redisson.config.Config;
import java.util.ArrayList;
import java.util.List;
/**
* 主从方式Redisson配置
* <p>配置方式: 127.0.0.1:6379(主),127.0.0.1:6380(子),127.0.0.1:6381(子)</p>
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
public class MasterslaveRedissonConfigStrategyImpl implements RedissonConfigStrategy {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase();
String[] addrTokens = address.split(",");
String masterNodeAddr = addrTokens[0];
// 设置主节点ip
config.useMasterSlaveServers().setMasterAddress(masterNodeAddr);
if (StringUtils.isNotBlank(password)) {
config.useMasterSlaveServers().setPassword(password);
}
config.useMasterSlaveServers().setDatabase(database);
// 设置从节点,移除第一个节点,默认第一个为主节点
List<String> slaveList = new ArrayList<>();
for (String addrToken : addrTokens) {
slaveList.add(GlobalConstant.REDIS_CONNECTION_PREFIX + addrToken);
}
slaveList.remove(0);
config.useMasterSlaveServers().addSlaveAddress((String[]) slaveList.toArray());
log.info("初始化主从方式Config,redisAddress:" + address);
} catch (Exception e) {
log.error("主从Redisson初始化错误", e);
e.printStackTrace();
}
return config;
}
}
@@ -0,0 +1,47 @@
package com.jero.boot.starter.lock.core.strategy.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.jero.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import com.jero.boot.starter.lock.prop.RedissonProperties;
import com.jero.boot.starter.lock.enums.GlobalConstant;
import org.redisson.config.Config;
/**
* 哨兵方式Redis连接配置
* 比如sentinel.conf里配置为sentinel monitor my-sentinel-name 127.0.0.1 6379 2,那么这里就配置my-sentinel-name
* 配置方式:my-sentinel-name,127.0.0.1:26379,127.0.0.1:26389,127.0.0.1:26399
* @author zyf
* @date 2020-11-11
*/
@Slf4j
public class SentinelRedissonConfigStrategyImpl implements RedissonConfigStrategy {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase();
String[] addrTokens = address.split(",");
String sentinelAliasName = addrTokens[0];
// 设置redis配置文件sentinel.conf配置的sentinel别名
config.useSentinelServers().setMasterName(sentinelAliasName);
config.useSentinelServers().setDatabase(database);
if (StringUtils.isNotBlank(password)) {
config.useSentinelServers().setPassword(password);
}
// 设置哨兵节点的服务IP和端口
for (int i = 1; i < addrTokens.length; i++) {
config.useSentinelServers().addSentinelAddress(GlobalConstant.REDIS_CONNECTION_PREFIX+ addrTokens[i]);
}
log.info("初始化哨兵方式Config,redisAddress:" + address);
} catch (Exception e) {
log.error("哨兵Redisson初始化错误", e);
e.printStackTrace();
}
return config;
}
}
@@ -0,0 +1,40 @@
package com.jero.boot.starter.lock.core.strategy.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.jero.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import com.jero.boot.starter.lock.prop.RedissonProperties;
import com.jero.boot.starter.lock.enums.GlobalConstant;
import org.redisson.config.Config;
/**
* 单机方式Redisson配置
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
public class StandaloneRedissonConfigStrategyImpl implements RedissonConfigStrategy {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase();
String redisAddr = GlobalConstant.REDIS_CONNECTION_PREFIX + address;
config.useSingleServer().setAddress(redisAddr);
config.useSingleServer().setDatabase(database);
if (StringUtils.isNotBlank(password)) {
config.useSingleServer().setPassword(password);
}
log.info("初始化Redisson单机配置,连接地址:" + address);
} catch (Exception e) {
log.error("单机Redisson初始化错误", e);
e.printStackTrace();
}
return config;
}
}
@@ -0,0 +1,17 @@
package com.jero.boot.starter.lock.enums;
/**
* 全局常量枚举
*
* @author zyf
* @date 2020-11-11
*/
public interface GlobalConstant {
/**
* Redis地址连接前缀
*/
String REDIS_CONNECTION_PREFIX = "redis://";
}
@@ -0,0 +1,22 @@
package com.jero.boot.starter.lock.enums;
/**
* 锁的模式
* @author jeecg
*/
public enum LockModel {
//可重入锁
REENTRANT,
//公平锁
FAIR,
//联锁(可以把一组锁当作一个锁来加锁和释放)
MULTIPLE,
//红锁
REDLOCK,
//读锁
READ,
//写锁
WRITE,
//自动模式,当参数只有一个.使用 REENTRANT 参数多个 REDLOCK
AUTO
}
@@ -0,0 +1,39 @@
package com.jero.boot.starter.lock.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Redis连接方式
* @author zyf
* @date 2020-11-11
*/
@Getter
@AllArgsConstructor
public enum RedisConnectionType {
/**
* 单机部署方式(默认)
*/
STANDALONE("standalone", "单机部署方式"),
/**
* 哨兵部署方式
*/
SENTINEL("sentinel", "哨兵部署方式"),
/**
* 集群部署方式
*/
CLUSTER("cluster", "集群方式"),
/**
* 主从部署方式
*/
MASTERSLAVE("masterslave", "主从部署方式");
/**
* 编码
*/
private final String code;
/**
* 名称
*/
private final String name;
}
@@ -0,0 +1,39 @@
package com.jero.boot.starter.lock.prop;
import lombok.Data;
import com.jero.boot.starter.lock.enums.RedisConnectionType;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Redisson配置映射类
*
* @author zyf
* @date 2020-11-11
*/
@Data
@ConfigurationProperties(prefix = "jeecg.redisson")
public class RedissonProperties {
/**
* redis主机地址,ipport,多个用逗号(,)分隔
*/
private String address;
/**
* 连接类型
*/
private RedisConnectionType type;
/**
* 密码
*/
private String password;
/**
* 数据库(默认0)
*/
private int database;
/**
* 是否装配redisson配置
*/
private Boolean enabled = true;
}