Redis分布锁锁加入Redisson优化

v1.4.1
Parker 5 years ago
parent ffbacc697e
commit c4bba95fad

@ -54,6 +54,13 @@
<version>${plugins.version}</version> <version>${plugins.version}</version>
</dependency> </dependency>
<!-- 引入软防火墙插件 -->
<dependency>
<groupId>org.opsliframework.boot</groupId>
<artifactId>opsli-plugins-waf</artifactId>
<version>${plugins.version}</version>
</dependency>
<!-- ———————————————————— 集成Shiro鉴权安全认证 - 开始 ———————————————————— --> <!-- ———————————————————— 集成Shiro鉴权安全认证 - 开始 ———————————————————— -->
<dependency> <dependency>
<groupId>org.crazycake</groupId> <groupId>org.crazycake</groupId>
@ -77,4 +84,4 @@
</dependencies> </dependencies>
</project> </project>

@ -31,9 +31,6 @@ public class GlobalProperties {
/** 是否开启演示模式 */ /** 是否开启演示模式 */
private boolean enableDemo; private boolean enableDemo;
/** 软防火墙 */
private Waf waf;
/** 认证类 */ /** 认证类 */
private Auth auth; private Auth auth;
@ -46,33 +43,6 @@ public class GlobalProperties {
// ============== 内部类 ============= // ============== 内部类 =============
/**
*
*/
@Data
@EqualsAndHashCode(callSuper = false)
public static class Waf {
/** 是否生效 */
private boolean enable;
/** xss 过滤 */
private boolean xssFilter;
/** sql 过滤 */
private boolean sqlFilter;
/** 过滤器需要过滤的路径 */
private Set<String> urlPatterns;
/** 过滤器需要排除过滤的路径 */
private Set<String> urlExclusion;
/** 过滤器的优先级,值越小优先级越高 */
private int order;
}
/** /**
* Web * Web
*/ */

@ -120,7 +120,7 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
// 如果开启缓存 先从缓存读 // 如果开启缓存 先从缓存读
if(hotDataFlag){ if(hotDataFlag){
model = WrapperUtil.transformInstance( model = WrapperUtil.transformInstance(
CacheUtil.getTimed(entityClazz, CacheConstants.HOT_DATA_PREFIX +":"+ id) CacheUtil.getTimed(entityClazz, CacheConstants.HOT_DATA_PREFIX +"::"+ id)
, modelClazz); , modelClazz);
if(model != null){ if(model != null){
return model; return model;
@ -130,12 +130,12 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
boolean hasNilFlag = false; boolean hasNilFlag = false;
// 如果开启缓存 防止缓存穿透判断 // 如果开启缓存 防止缓存穿透判断
if(hotDataFlag){ if(hotDataFlag){
hasNilFlag = CacheUtil.hasNilFlag("get:" + id); hasNilFlag = CacheUtil.hasNilFlag("get::" + id);
} }
if(!hasNilFlag){ if(!hasNilFlag){
// 锁凭证 redisLock 贯穿全程 // 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock(); RedisLock redisLock = new RedisLock();
redisLock.setLockName("getLock:"+id) redisLock.setLockName("getLock::"+id)
.setAcquireTimeOut(3000L) .setAcquireTimeOut(3000L)
.setLockTimeOut(10000L); .setLockTimeOut(10000L);
// 这里增加分布式锁 防止缓存击穿 // 这里增加分布式锁 防止缓存击穿
@ -149,7 +149,7 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
model = WrapperUtil.transformInstance( model = WrapperUtil.transformInstance(
CacheUtil.getTimed(entityClazz, CacheConstants.HOT_DATA_PREFIX +":"+ id) CacheUtil.getTimed(entityClazz, CacheConstants.HOT_DATA_PREFIX +"::"+ id)
, modelClazz); , modelClazz);
if(model != null){ if(model != null){
return model; return model;
@ -178,7 +178,7 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
} }
}else { }else {
// 设置空变量 用于防止穿透判断 // 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag("get:" + id); CacheUtil.putNilFlag("get::" + id);
} }
} }
} }

@ -299,7 +299,7 @@ public class CacheUtil {
if(isSaveLocal){ if(isSaveLocal){
// 获得缓存Json // 获得缓存Json
cacheJson = ehCachePlugin.get(CacheConstants.EHCACHE_SPACE, cacheJson = ehCachePlugin.get(CacheConstants.EHCACHE_SPACE,
cacheKey +":"+ field, JSONObject.class); cacheKey +"::"+ field, JSONObject.class);
if(cacheJson != null){ if(cacheJson != null){
return cacheJson.get(JSON_KEY); return cacheJson.get(JSON_KEY);
} }
@ -312,7 +312,7 @@ public class CacheUtil {
if(isSaveLocal){ if(isSaveLocal){
//存入EhCache //存入EhCache
ehCachePlugin.put(CacheConstants.EHCACHE_SPACE, ehCachePlugin.put(CacheConstants.EHCACHE_SPACE,
cacheKey + ":" + field, cacheJson); cacheKey + "::" + field, cacheJson);
} }
} }
@ -474,7 +474,7 @@ public class CacheUtil {
String cacheKey = CacheUtil.handleKey(CacheType.EDEN_HASH, key); String cacheKey = CacheUtil.handleKey(CacheType.EDEN_HASH, key);
// 删除 EhCache // 删除 EhCache
boolean ehcacheRet = ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE,cacheKey +":"+ field); boolean ehcacheRet = ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE,cacheKey +"::"+ field);
if(ehcacheRet){ if(ehcacheRet){
count--; count--;
} }
@ -504,7 +504,7 @@ public class CacheUtil {
public static boolean putNilFlag(String key) { public static boolean putNilFlag(String key) {
try { try {
// 处理缓存 key // 处理缓存 key
String cacheKey = CacheUtil.handleKey(NIL_FLAG_PREFIX + ":" + key); String cacheKey = CacheUtil.handleKey(NIL_FLAG_PREFIX + "::" + key);
// 存入Redis // 存入Redis
return redisPlugin.put(cacheKey, 1, TTL_NIL_DATA_TIME); return redisPlugin.put(cacheKey, 1, TTL_NIL_DATA_TIME);
}catch (Exception e){ }catch (Exception e){
@ -523,7 +523,7 @@ public class CacheUtil {
public static boolean delNilFlag(String key) { public static boolean delNilFlag(String key) {
try { try {
// 处理缓存 key // 处理缓存 key
String cacheKey = CacheUtil.handleKey(NIL_FLAG_PREFIX + ":" + key); String cacheKey = CacheUtil.handleKey(NIL_FLAG_PREFIX + "::" + key);
// 删除Redis // 删除Redis
return redisPlugin.del(cacheKey); return redisPlugin.del(cacheKey);
}catch (Exception e){ }catch (Exception e){
@ -543,7 +543,7 @@ public class CacheUtil {
public static boolean hasNilFlag(String key) { public static boolean hasNilFlag(String key) {
try { try {
// 处理缓存 key // 处理缓存 key
String cacheKey = CacheUtil.handleKey(NIL_FLAG_PREFIX + ":" + key); String cacheKey = CacheUtil.handleKey(NIL_FLAG_PREFIX + "::" + key);
// 判断Redis 是否 包含当前Nil值 // 判断Redis 是否 包含当前Nil值
return redisPlugin.get(cacheKey) != null; return redisPlugin.get(cacheKey) != null;
}catch (Exception e){ }catch (Exception e){
@ -571,7 +571,7 @@ public class CacheUtil {
* @return String * @return String
*/ */
public static String handleKey(CacheType cacheType, String key){ public static String handleKey(CacheType cacheType, String key){
return PREFIX_NAME + cacheType.getName() + ":" + return PREFIX_NAME + cacheType.getName() + "::" +
key; key;
} }

@ -85,9 +85,9 @@ public class DictHandler implements RedisPushSubHandler{
// 解析 key // 解析 key
String ehKeyByName = CacheUtil.handleKey(CacheType.EDEN_HASH, DictConstants.CACHE_PREFIX_NAME + String ehKeyByName = CacheUtil.handleKey(CacheType.EDEN_HASH, DictConstants.CACHE_PREFIX_NAME +
dictWrapperModel.getTypeCode() + ":" + dictWrapperModel.getDictName()); dictWrapperModel.getTypeCode() + "::" + dictWrapperModel.getDictName());
String ehKeyByValue = CacheUtil.handleKey(CacheType.EDEN_HASH, DictConstants.CACHE_PREFIX_VALUE + String ehKeyByValue = CacheUtil.handleKey(CacheType.EDEN_HASH, DictConstants.CACHE_PREFIX_VALUE +
dictWrapperModel.getTypeCode() + ":" + dictWrapperModel.getDictValue()); dictWrapperModel.getTypeCode() + "::" + dictWrapperModel.getDictValue());
// 缓存更新 // 缓存更新
if(CacheHandleType.UPDATE == type){ if(CacheHandleType.UPDATE == type){

@ -55,7 +55,7 @@ public class HotDataHandler implements RedisPushSubHandler{
} }
// 拼装缓存key // 拼装缓存key
String cacheName = CacheUtil.handleKey(CacheConstants.HOT_DATA_PREFIX +":"+ key); String cacheName = CacheUtil.handleKey(CacheConstants.HOT_DATA_PREFIX +"::"+ key);
if(CacheHandleType.UPDATE == type){ if(CacheHandleType.UPDATE == type){
ehCachePlugin.put(CacheConstants.EHCACHE_SPACE, cacheName, value); ehCachePlugin.put(CacheConstants.EHCACHE_SPACE, cacheName, value);

@ -93,7 +93,7 @@ public class CacheDataAop {
for (CacheDataEntity cacheDataEntity : cacheDataEntityList) { for (CacheDataEntity cacheDataEntity : cacheDataEntityList) {
// 更新缓存数据 // 更新缓存数据
// 热点数据 // 热点数据
boolean putRet = CacheUtil.put(CacheConstants.HOT_DATA_PREFIX +":"+ cacheDataEntity.getKey(), boolean putRet = CacheUtil.put(CacheConstants.HOT_DATA_PREFIX +"::"+ cacheDataEntity.getKey(),
returnValue); returnValue);
if(putRet){ if(putRet){
// 广播缓存数据 - 通知其他服务器同步数据 // 广播缓存数据 - 通知其他服务器同步数据
@ -143,7 +143,7 @@ public class CacheDataAop {
for (CacheDataEntity cacheDataEntity : cacheDataEntityList) { for (CacheDataEntity cacheDataEntity : cacheDataEntityList) {
// 更新缓存数据 - 删除缓存 // 更新缓存数据 - 删除缓存
boolean delRet = CacheUtil.del(CacheConstants.HOT_DATA_PREFIX +":"+ cacheDataEntity.getKey()); boolean delRet = CacheUtil.del(CacheConstants.HOT_DATA_PREFIX +"::"+ cacheDataEntity.getKey());
if(delRet){ if(delRet){
// 广播缓存数据 - 通知其他服务器同步数据 // 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage( redisPlugin.sendMessage(

@ -59,12 +59,6 @@ public enum CoreMsg implements BaseMsg {
CACHE_DEL_EXCEPTION(10406, "无法清除缓存,请稍后再试"), CACHE_DEL_EXCEPTION(10406, "无法清除缓存,请稍后再试"),
/**
*
*/
WAF_EXCEPTION_XSS(10500, "包含非法字符!"),
WAF_EXCEPTION_SQL(10501, "包含非法字符!"),
/** 演示模式 */ /** 演示模式 */
EXCEPTION_ENABLE_DEMO(10600,"演示模式不允许操作"), EXCEPTION_ENABLE_DEMO(10600,"演示模式不允许操作"),

@ -45,7 +45,7 @@ public class RedisCacheManager implements CacheManager {
Cache cache = caches.get(name); Cache cache = caches.get(name);
if (cache == null) { if (cache == null) {
cache = new RedisCache<K, V>(redisManager,keyPrefix + name + ":", expire, principalIdFieldName); cache = new RedisCache<K, V>(redisManager,keyPrefix + name + "::", expire, principalIdFieldName);
caches.put(name, cache); caches.put(name, cache);
} }
return cache; return cache;
@ -82,4 +82,4 @@ public class RedisCacheManager implements CacheManager {
public void setPrincipalIdFieldName(String principalIdFieldName) { public void setPrincipalIdFieldName(String principalIdFieldName) {
this.principalIdFieldName = principalIdFieldName; this.principalIdFieldName = principalIdFieldName;
} }
} }

@ -25,10 +25,10 @@ package org.opsli.core.security.shiro.utils;
public class RedisKeys { public class RedisKeys {
public static String getSysConfigKey(String key){ public static String getSysConfigKey(String key){
return "system:config:" + key; return "system::config::" + key;
} }
public static String getShiroSessionKey(String key){ public static String getShiroSessionKey(String key){
return "sessionid:" + key; return "sessionid::" + key;
} }
} }

@ -17,6 +17,7 @@ package org.opsli.core.utils;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -28,9 +29,8 @@ import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.common.constants.DictConstants; import org.opsli.common.constants.DictConstants;
import org.opsli.common.enums.CacheType; import org.opsli.common.enums.CacheType;
import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.cache.local.CacheUtil;
import org.opsli.plugins.redis.RedisLockPlugins; import org.opsli.core.msg.CoreMsg;
import org.opsli.plugins.redis.RedisPlugin; import org.opsli.plugins.redis.RedisPlugin;
import org.opsli.plugins.redis.lock.RedisLock;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
@ -38,7 +38,6 @@ import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static org.opsli.common.constants.OrderConstants.UTIL_ORDER; import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
@ -58,9 +57,6 @@ public class DictUtil {
/** Redis插件 */ /** Redis插件 */
private static RedisPlugin redisPlugin; private static RedisPlugin redisPlugin;
/** Redis分布式锁 */
private static RedisLockPlugins redisLockPlugins;
/** 字典Service */ /** 字典Service */
private static DictDetailApi dictDetailApi; private static DictDetailApi dictDetailApi;
@ -70,51 +66,46 @@ public class DictUtil {
* @param typeCode Code * @param typeCode Code
* @param dictValue * @param dictValue
* @param defaultVal * @param defaultVal
* @return * @return String
*/ */
public static String getDictNameByValue(String typeCode, String dictValue, String defaultVal){ public static String getDictNameByValue(String typeCode, String dictValue, String defaultVal){
// 缓存Key
String cacheKey = DictConstants.CACHE_PREFIX_VALUE + typeCode;
// 缓存Key + VALUE
String cacheKeyVal = cacheKey + "::" + dictValue;
// 字典名称
String dictName = null;
String dictName = ""; DictDetailModel cacheModel = CacheUtil.getHash(DictDetailModel.class, cacheKey,
DictDetailModel cacheModel = CacheUtil.getHash(DictDetailModel.class, DictConstants.CACHE_PREFIX_VALUE + typeCode,
dictValue); dictValue);
if (cacheModel != null){ // 如果缓存有值 直接返回
dictName = cacheModel.getDictName(); if (cacheModel != null &&
StringUtils.isNotEmpty(cacheModel.getDictName())){
return cacheModel.getDictName();
} }
if (StringUtils.isNotEmpty(dictName)){
return dictName;
}
// 防止缓存穿透判断 // 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(DictConstants.CACHE_PREFIX_VALUE + typeCode + ":" + dictValue); boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKeyVal);
if(hasNilFlag){ if(hasNilFlag){
return defaultVal; return defaultVal;
} }
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(DictConstants.CACHE_PREFIX_VALUE + typeCode + ":" + dictValue)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try { try {
// 这里增加分布式锁 防止缓存击穿 // 分布式加锁
// ============ 尝试加锁 if(!DistributedLockUtil.lock(cacheKeyVal)){
redisLock = redisLockPlugins.tryLock(redisLock); // 无法申领分布式锁
if(redisLock == null){ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return defaultVal; return null;
} }
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
cacheModel = CacheUtil.getHash(DictDetailModel.class, DictConstants.CACHE_PREFIX_VALUE + typeCode, cacheModel = CacheUtil.getHash(DictDetailModel.class, cacheKey,
dictValue); dictValue);
if (cacheModel != null){ // 如果缓存有值 直接返回
dictName = cacheModel.getDictName(); if (cacheModel != null &&
} StringUtils.isNotEmpty(cacheModel.getDictName())){
if (StringUtils.isNotEmpty(dictName)){ return cacheModel.getDictName();
return dictName;
} }
// 查询数据库 并保存到缓存内 // 查询数据库 并保存到缓存内
@ -123,15 +114,10 @@ public class DictUtil {
List<DictDetailModel> dictDetailModels = resultVo.getData(); List<DictDetailModel> dictDetailModels = resultVo.getData();
for (DictDetailModel model : dictDetailModels) { for (DictDetailModel model : dictDetailModels) {
if(model.getDictValue().equals(dictValue)){ if(model.getDictValue().equals(dictValue)){
// 名称
dictName = model.getDictName();
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(model.getTypeCode());
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(model);
// 保存至缓存 // 保存至缓存
DictUtil.put(dictWrapperModel); DictWrapper dictWrapper = DictUtil.putByModel(model);
// 缓存名
dictName = dictWrapper.getDictName();
break; break;
} }
} }
@ -141,15 +127,15 @@ public class DictUtil {
log.error(e.getMessage(),e); log.error(e.getMessage(),e);
return defaultVal; return defaultVal;
}finally { }finally {
// ============ 释放锁 // 释放锁
redisLockPlugins.unLock(redisLock); DistributedLockUtil.unlock(cacheKeyVal);
} }
// 如果名称还是 为空 则赋默认值 // 如果名称还是 为空 则赋默认值
if(StringUtils.isEmpty(dictName)){ if(StringUtils.isEmpty(dictName)){
// 加入缓存防穿透 // 加入缓存防穿透
// 设置空变量 用于防止穿透判断 // 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(DictConstants.CACHE_PREFIX_VALUE + typeCode + ":" + dictValue); CacheUtil.putNilFlag(cacheKeyVal);
dictName = defaultVal; dictName = defaultVal;
} }
return dictName; return dictName;
@ -160,48 +146,45 @@ public class DictUtil {
* @param typeCode Code * @param typeCode Code
* @param dictName * @param dictName
* @param defaultVal * @param defaultVal
* @return * @return String
*/ */
public static String getDictValueByName(String typeCode, String dictName, String defaultVal){ public static String getDictValueByName(String typeCode, String dictName, String defaultVal){
// 缓存Key
String cacheKey = DictConstants.CACHE_PREFIX_NAME + typeCode;
// 缓存Key + VALUE
String cacheKeyVal = cacheKey + "::" + dictName;
// 字典值
String dictValue = null;
String dictValue = ""; DictDetailModel cacheModel = CacheUtil.getHash(DictDetailModel.class, cacheKey,
DictDetailModel cacheModel = CacheUtil.getHash(DictDetailModel.class, DictConstants.CACHE_PREFIX_NAME + typeCode,
dictName); dictName);
if (cacheModel != null){ // 如果缓存有值 直接返回
dictValue = cacheModel.getDictValue(); if (cacheModel != null &&
} StringUtils.isNotEmpty(cacheModel.getDictValue())){
if (StringUtils.isNotEmpty(dictValue)){ return cacheModel.getDictValue();
return dictValue;
} }
// 防止缓存穿透判断 // 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(DictConstants.CACHE_PREFIX_NAME + typeCode + ":" + dictName); boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKeyVal);
if(hasNilFlag){ if(hasNilFlag){
return defaultVal; return defaultVal;
} }
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(DictConstants.CACHE_PREFIX_NAME + typeCode + ":" + dictName)
.setAcquireTimeOut(3000L)
.setLockTimeOut(10000L);
try { try {
// 这里增加分布式锁 防止缓存击穿 // 分布式加锁
// ============ 尝试加锁 if(!DistributedLockUtil.lock(cacheKeyVal)){
redisLock = redisLockPlugins.tryLock(redisLock); // 无法申领分布式锁
if(redisLock == null){ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return defaultVal; return null;
} }
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 cacheModel = CacheUtil.getHash(DictDetailModel.class, cacheKey,
cacheModel = CacheUtil.getHash(DictDetailModel.class, DictConstants.CACHE_PREFIX_NAME + typeCode,
dictName); dictName);
if (cacheModel != null){ // 如果缓存有值 直接返回
dictValue = cacheModel.getDictValue(); if (cacheModel != null &&
} StringUtils.isNotEmpty(cacheModel.getDictValue())){
if (StringUtils.isNotEmpty(dictValue)){ return cacheModel.getDictValue();
return dictValue;
} }
// 查询数据库 并保存到缓存内 // 查询数据库 并保存到缓存内
@ -210,15 +193,10 @@ public class DictUtil {
List<DictDetailModel> dictDetailModels = resultVo.getData(); List<DictDetailModel> dictDetailModels = resultVo.getData();
for (DictDetailModel model : dictDetailModels) { for (DictDetailModel model : dictDetailModels) {
if(model.getDictName().equals(dictName)){ if(model.getDictName().equals(dictName)){
// 值
dictValue = model.getDictValue();
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(model.getTypeCode());
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(model);
// 保存至缓存 // 保存至缓存
DictUtil.put(dictWrapperModel); DictWrapper dictWrapper = DictUtil.putByModel(model);
// 值
dictValue = dictWrapper.getDictValue();
break; break;
} }
} }
@ -228,16 +206,15 @@ public class DictUtil {
log.error(e.getMessage(),e); log.error(e.getMessage(),e);
return defaultVal; return defaultVal;
}finally { }finally {
// ============ 释放锁 // 释放锁
redisLockPlugins.unLock(redisLock); DistributedLockUtil.unlock(cacheKeyVal);
} }
// 如果值还是 为空 则赋默认值 // 如果值还是 为空 则赋默认值
if(StringUtils.isEmpty(dictValue)){ if(StringUtils.isEmpty(dictValue)){
// 加入缓存防穿透 // 加入缓存防穿透
// 设置空变量 用于防止穿透判断 // 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(DictConstants.CACHE_PREFIX_NAME + typeCode + ":" + dictName); CacheUtil.putNilFlag(cacheKeyVal);
dictValue = defaultVal; dictValue = defaultVal;
} }
return dictValue; return dictValue;
@ -245,82 +222,42 @@ public class DictUtil {
/** /**
* code * code
* @param typeCode * @param typeCode
* @return * @return List
*/ */
public static List<DictWrapper> getDictList(String typeCode){ public static List<DictWrapper> getDictList(String typeCode){
List<DictWrapper> dictWrapperModels = Lists.newArrayList(); // 缓存Key
String cacheKey = DictConstants.CACHE_PREFIX_NAME + typeCode;
List<DictWrapper> dictWrapperModels;
try { try {
String key = CacheUtil.handleKey(CacheType.EDEN_HASH, DictConstants.CACHE_PREFIX_VALUE + typeCode); String key = CacheUtil.handleKey(CacheType.EDEN_HASH, cacheKey);
Map<Object, Object> dictMap = redisPlugin.hGetAll(key); // 处理集合数据
Set<Map.Entry<Object, Object>> entries = dictMap.entrySet(); dictWrapperModels = handleDictList(redisPlugin.hGetAll(key), typeCode);
for (Map.Entry<Object, Object> entry : entries) { if(CollUtil.isNotEmpty(dictWrapperModels)){
// 赋值 return dictWrapperModels;
JSONObject jsonObject = (JSONObject) entry.getValue();
if(jsonObject == null){
continue;
}
JSONObject dataJson = jsonObject.getJSONObject(CacheUtil.JSON_KEY);
if(dataJson == null){
continue;
}
DictDetailModel model = dataJson.toJavaObject(DictDetailModel.class);
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(typeCode);
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModels.add(dictWrapperModel);
}
if(!dictWrapperModels.isEmpty()){
// 排序
return sortDictWrappers(dictWrapperModels);
} }
// 防止缓存穿透判断 // 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(DictConstants.CACHE_PREFIX_LIST + typeCode); boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){ if(hasNilFlag){
return dictWrapperModels; return dictWrapperModels;
} }
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(DictConstants.CACHE_PREFIX_LIST + typeCode)
.setAcquireTimeOut(3000L)
.setLockTimeOut(10000L);
try { try {
// 这里增加分布式锁 防止缓存击穿 // 分布式加锁
// ============ 尝试加锁 if(!DistributedLockUtil.lock(cacheKey)){
redisLock = redisLockPlugins.tryLock(redisLock); // 无法申领分布式锁
if(redisLock == null){ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return dictWrapperModels; return dictWrapperModels;
} }
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
key = CacheUtil.handleKey(CacheType.EDEN_HASH, DictConstants.CACHE_PREFIX_VALUE + typeCode); key = CacheUtil.handleKey(CacheType.EDEN_HASH, cacheKey);
dictMap = redisPlugin.hGetAll(key); // 处理集合数据
entries = dictMap.entrySet(); dictWrapperModels = handleDictList(redisPlugin.hGetAll(key), typeCode);
for (Map.Entry<Object, Object> entry : entries) { if(CollUtil.isNotEmpty(dictWrapperModels)){
// 赋值 return dictWrapperModels;
JSONObject jsonObject = (JSONObject) entry.getValue();
if(jsonObject == null){
continue;
}
JSONObject dataJson = jsonObject.getJSONObject(CacheUtil.JSON_KEY);
if(dataJson == null){
continue;
}
DictDetailModel model = dataJson.toJavaObject(DictDetailModel.class);
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(typeCode);
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(model);
dictWrapperModels.add(dictWrapperModel);
}
if(!dictWrapperModels.isEmpty()){
// 排序
return sortDictWrappers(dictWrapperModels);
} }
@ -328,15 +265,14 @@ public class DictUtil {
ResultVo<List<DictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode); ResultVo<List<DictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
if(resultVo.isSuccess()){ if(resultVo.isSuccess()){
List<DictDetailModel> dictDetailModels = resultVo.getData(); List<DictDetailModel> dictDetailModels = resultVo.getData();
for (DictDetailModel model : dictDetailModels) { // 处理数据库查询数据
DictWrapper dictWrapperModel = new DictWrapper(); if(CollUtil.isNotEmpty(dictDetailModels)){
dictWrapperModel.setTypeCode(model.getTypeCode()); dictWrapperModels = Lists.newArrayListWithCapacity(dictDetailModels.size());
dictWrapperModel.setDictName(model.getDictName()); for (DictDetailModel model : dictDetailModels) {
dictWrapperModel.setDictValue(model.getDictValue()); // 保存至缓存
dictWrapperModel.setModel(model); DictWrapper dictWrapper = DictUtil.putByModel(model);
dictWrapperModels.add(dictWrapperModel); dictWrapperModels.add(dictWrapper);
// 保存至缓存 }
DictUtil.put(dictWrapperModel);
} }
} }
@ -344,16 +280,16 @@ public class DictUtil {
log.error(e.getMessage(),e); log.error(e.getMessage(),e);
return dictWrapperModels; return dictWrapperModels;
}finally { }finally {
// ============ 释放锁 // 释放锁
redisLockPlugins.unLock(redisLock); DistributedLockUtil.unlock(cacheKey);
} }
// 如果值还是 为空 则赋默认值 // 如果值还是 为空 则赋默认值
if(dictWrapperModels.isEmpty()){ if(CollUtil.isEmpty(dictWrapperModels)){
// 加入缓存防穿透 // 加入缓存防穿透
// 设置空变量 用于防止穿透判断 // 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(DictConstants.CACHE_PREFIX_LIST + typeCode ); CacheUtil.putNilFlag(cacheKey);
} }
}catch (Exception e){ }catch (Exception e){
@ -367,10 +303,14 @@ public class DictUtil {
/** /**
* *
* @param dictWrapperModels * @param dictWrapperModels Model
* @return * @return List
*/ */
private static List<DictWrapper> sortDictWrappers(List<DictWrapper> dictWrapperModels) { private static List<DictWrapper> sortDictWrappers(List<DictWrapper> dictWrapperModels) {
// 非法判读
if(dictWrapperModels == null){
return null;
}
ListUtil.sort(dictWrapperModels, (o1, o2) -> { ListUtil.sort(dictWrapperModels, (o1, o2) -> {
int oInt1 = Integer.MAX_VALUE; int oInt1 = Integer.MAX_VALUE;
int oInt2 = Integer.MAX_VALUE; int oInt2 = Integer.MAX_VALUE;
@ -392,7 +332,21 @@ public class DictUtil {
/** /**
* *
* @param model * @param model
* @return */
private static DictWrapper putByModel(DictDetailModel model){
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(model.getTypeCode());
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(model);
// 保存至缓存
DictUtil.put(dictWrapperModel);
return dictWrapperModel;
}
/**
*
* @param model
*/ */
public static void put(DictWrapper model){ public static void put(DictWrapper model){
// 清除缓存 // 清除缓存
@ -407,7 +361,7 @@ public class DictUtil {
/** /**
* *
* @param model * @param model
* @return * @return boolean
*/ */
public static boolean del(DictWrapper model){ public static boolean del(DictWrapper model){
if(model == null){ if(model == null){
@ -415,9 +369,9 @@ public class DictUtil {
} }
boolean hasNilFlagByName = CacheUtil.hasNilFlag(DictConstants.CACHE_PREFIX_NAME + boolean hasNilFlagByName = CacheUtil.hasNilFlag(DictConstants.CACHE_PREFIX_NAME +
model.getTypeCode() + ":" + model.getDictName()); model.getTypeCode() + "::" + model.getDictName());
boolean hasNilFlagByValue = CacheUtil.hasNilFlag(DictConstants.CACHE_PREFIX_VALUE + boolean hasNilFlagByValue = CacheUtil.hasNilFlag(DictConstants.CACHE_PREFIX_VALUE +
model.getTypeCode() + ":" + model.getDictValue()); model.getTypeCode() + "::" + model.getDictValue());
DictWrapper dictByName = CacheUtil.getHash(DictWrapper.class, DictWrapper dictByName = CacheUtil.getHash(DictWrapper.class,
DictConstants.CACHE_PREFIX_NAME + model.getTypeCode(), DictConstants.CACHE_PREFIX_NAME + model.getTypeCode(),
@ -432,7 +386,7 @@ public class DictUtil {
count++; count++;
// 清除空拦截 // 清除空拦截
boolean tmp = CacheUtil.delNilFlag(DictConstants.CACHE_PREFIX_NAME + boolean tmp = CacheUtil.delNilFlag(DictConstants.CACHE_PREFIX_NAME +
model.getTypeCode() + ":" + model.getDictName()); model.getTypeCode() + "::" + model.getDictName());
if(tmp){ if(tmp){
count--; count--;
} }
@ -442,7 +396,7 @@ public class DictUtil {
count++; count++;
// 清除空拦截 // 清除空拦截
boolean tmp = CacheUtil.delNilFlag(DictConstants.CACHE_PREFIX_VALUE + boolean tmp = CacheUtil.delNilFlag(DictConstants.CACHE_PREFIX_VALUE +
model.getTypeCode() + ":" + model.getDictValue()); model.getTypeCode() + "::" + model.getDictValue());
if(tmp){ if(tmp){
count--; count--;
} }
@ -474,7 +428,7 @@ public class DictUtil {
/** /**
* typeCode * typeCode
* @param typeCode * @param typeCode
* @return * @return boolean
*/ */
public static boolean delAll(String typeCode){ public static boolean delAll(String typeCode){
List<DictWrapper> dictWrapperList = DictUtil.getDictList(typeCode); List<DictWrapper> dictWrapperList = DictUtil.getDictList(typeCode);
@ -493,6 +447,41 @@ public class DictUtil {
return count == 0; return count == 0;
} }
/***
*
* @param dictMap Map
* @param typeCode
* @return List
*/
public static List<DictWrapper> handleDictList(Map<Object, Object> dictMap, String typeCode){
if(CollUtil.isEmpty(dictMap)){
return null;
}
List<DictWrapper> dictWrapperModels = Lists.newArrayList();
for (Map.Entry<Object, Object> entry : dictMap.entrySet()) {
// 赋值
JSONObject jsonObject = (JSONObject) entry.getValue();
if(jsonObject == null){
continue;
}
Object data = jsonObject.get(CacheUtil.JSON_KEY);
if(data == null){
continue;
}
DictDetailModel model = Convert.convert(DictDetailModel.class, data);
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(typeCode);
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModels.add(dictWrapperModel);
}
// 返回排序后 list
return CollUtil.isNotEmpty(dictWrapperModels)?sortDictWrappers(dictWrapperModels):null;
}
// =================================== // ===================================
@ -501,13 +490,9 @@ public class DictUtil {
DictUtil.redisPlugin = redisPlugin; DictUtil.redisPlugin = redisPlugin;
} }
@Autowired
public void setRedisLockPlugins(RedisLockPlugins redisLockPlugins) {
DictUtil.redisLockPlugins = redisLockPlugins;
}
@Autowired @Autowired
public void setDictDetailApi(DictDetailApi dictDetailApi) { public void setDictDetailApi(DictDetailApi dictDetailApi) {
DictUtil.dictDetailApi = dictDetailApi; DictUtil.dictDetailApi = dictDetailApi;
} }
} }

@ -0,0 +1,91 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.user.UserApi;
import org.opsli.api.wrapper.system.user.UserOrgRefModel;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.msgs.OrgMsgFactory;
import org.opsli.core.msg.CoreMsg;
import org.opsli.plugins.redis.RedisPlugin;
import org.opsli.plugins.redisson.RedissonLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.core.utils
* @Author: Parker
* @CreateTime: 2020-09-19 20:03
* @Description:
*/
@Slf4j
@Order(UTIL_ORDER)
@Component
@Lazy(false)
public class DistributedLockUtil {
/** 锁有效时长为 默认10秒 */
private static final int LEASE_TIME = 10;
/** Redisson 分布式锁 */
private static RedissonLock REDISSON_LOCK;
/**
*
* @param lockName
* @return boolean
*/
public static boolean lock(String lockName){
boolean isLock = true;
// 分布式上锁
if(REDISSON_LOCK != null){
isLock = REDISSON_LOCK.tryLock(CacheUtil.getPrefixName() + lockName, LEASE_TIME);
}
return isLock;
}
/**
*
* @param lockName
*/
public static void unlock(String lockName){
// 释放锁
if(REDISSON_LOCK != null){
REDISSON_LOCK.unlockByThread(CacheUtil.getPrefixName() + lockName);
}
}
// =============
/**
*
* @param redissonLock
*/
@Autowired
public void init(RedissonLock redissonLock){
DistributedLockUtil.REDISSON_LOCK = redissonLock;
}
}

@ -22,9 +22,8 @@ import org.opsli.api.web.system.menu.MenuApi;
import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.msgs.MenuMsgFactory; import org.opsli.core.cache.pushsub.msgs.MenuMsgFactory;
import org.opsli.plugins.redis.RedisLockPlugins; import org.opsli.core.msg.CoreMsg;
import org.opsli.plugins.redis.RedisPlugin; import org.opsli.plugins.redis.RedisPlugin;
import org.opsli.plugins.redis.lock.RedisLock;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
@ -52,9 +51,6 @@ public class MenuUtil {
/** Redis插件 */ /** Redis插件 */
private static RedisPlugin redisPlugin; private static RedisPlugin redisPlugin;
/** Redis分布式锁 */
private static RedisLockPlugins redisLockPlugins;
/** 菜单 Api */ /** 菜单 Api */
private static MenuApi menuApi; private static MenuApi menuApi;
@ -65,35 +61,32 @@ public class MenuUtil {
* @return * @return
*/ */
public static MenuModel getMenuByCode(String menuCode){ public static MenuModel getMenuByCode(String menuCode){
// 缓存Key
String cacheKey = PREFIX_CODE + menuCode;
// 先从缓存里拿 // 先从缓存里拿
MenuModel menuModel = CacheUtil.getTimed(MenuModel.class, PREFIX_CODE + menuCode); MenuModel menuModel = CacheUtil.getTimed(MenuModel.class, cacheKey);
if (menuModel != null){ if (menuModel != null){
return menuModel; return menuModel;
} }
// 拿不到 -------- // 拿不到 --------
// 防止缓存穿透判断 // 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_CODE + menuCode); boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){ if(hasNilFlag){
return null; return null;
} }
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(PREFIX_CODE + menuCode)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try { try {
// 这里增加分布式锁 防止缓存击穿 // 分布式加锁
// ============ 尝试加锁 if(!DistributedLockUtil.lock(cacheKey)){
redisLock = redisLockPlugins.tryLock(redisLock); // 无法申领分布式锁
if(redisLock == null){ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null; return null;
} }
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
menuModel = CacheUtil.getTimed(MenuModel.class, PREFIX_CODE + menuCode); menuModel = CacheUtil.getTimed(MenuModel.class, cacheKey);
if (menuModel != null){ if (menuModel != null){
return menuModel; return menuModel;
} }
@ -103,18 +96,18 @@ public class MenuUtil {
if(resultVo.isSuccess()){ if(resultVo.isSuccess()){
menuModel = resultVo.getData(); menuModel = resultVo.getData();
// 存入缓存 // 存入缓存
CacheUtil.put(PREFIX_CODE + menuCode, menuModel); CacheUtil.put(cacheKey, menuModel);
} }
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage(),e); log.error(e.getMessage(),e);
}finally { }finally {
// ============ 释放锁 // 释放锁
redisLockPlugins.unLock(redisLock); DistributedLockUtil.unlock(cacheKey);
} }
if(menuModel == null){ if(menuModel == null){
// 设置空变量 用于防止穿透判断 // 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(PREFIX_CODE + menuCode); CacheUtil.putNilFlag(cacheKey);
return null; return null;
} }
@ -177,13 +170,9 @@ public class MenuUtil {
MenuUtil.redisPlugin = redisPlugin; MenuUtil.redisPlugin = redisPlugin;
} }
@Autowired
public void setRedisLockPlugins(RedisLockPlugins redisLockPlugins) {
MenuUtil.redisLockPlugins = redisLockPlugins;
}
@Autowired @Autowired
public void setMenuApi(MenuApi menuApi) { public void setMenuApi(MenuApi menuApi) {
MenuUtil.menuApi = menuApi; MenuUtil.menuApi = menuApi;
} }
} }

@ -22,9 +22,8 @@ import org.opsli.api.web.system.user.UserApi;
import org.opsli.api.wrapper.system.user.UserOrgRefModel; import org.opsli.api.wrapper.system.user.UserOrgRefModel;
import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.msgs.OrgMsgFactory; import org.opsli.core.cache.pushsub.msgs.OrgMsgFactory;
import org.opsli.plugins.redis.RedisLockPlugins; import org.opsli.core.msg.CoreMsg;
import org.opsli.plugins.redis.RedisPlugin; import org.opsli.plugins.redis.RedisPlugin;
import org.opsli.plugins.redis.lock.RedisLock;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
@ -52,9 +51,6 @@ public class OrgUtil {
/** Redis插件 */ /** Redis插件 */
private static RedisPlugin redisPlugin; private static RedisPlugin redisPlugin;
/** Redis分布式锁 */
private static RedisLockPlugins redisLockPlugins;
/** 用户 Api */ /** 用户 Api */
private static UserApi userApi; private static UserApi userApi;
@ -65,35 +61,32 @@ public class OrgUtil {
* @return * @return
*/ */
public static UserOrgRefModel getOrgByUserId(String userId){ public static UserOrgRefModel getOrgByUserId(String userId){
// 缓存Key
String cacheKey = PREFIX_CODE + userId;
// 先从缓存里拿 // 先从缓存里拿
UserOrgRefModel orgRefModel = CacheUtil.getTimed(UserOrgRefModel.class, PREFIX_CODE + userId); UserOrgRefModel orgRefModel = CacheUtil.getTimed(UserOrgRefModel.class, cacheKey);
if (orgRefModel != null){ if (orgRefModel != null){
return orgRefModel; return orgRefModel;
} }
// 拿不到 -------- // 拿不到 --------
// 防止缓存穿透判断 // 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_CODE + userId); boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){ if(hasNilFlag){
return null; return null;
} }
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(PREFIX_CODE + userId)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try { try {
// 这里增加分布式锁 防止缓存击穿 // 分布式加锁
// ============ 尝试加锁 if(!DistributedLockUtil.lock(cacheKey)){
redisLock = redisLockPlugins.tryLock(redisLock); // 无法申领分布式锁
if(redisLock == null){ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null; return null;
} }
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
orgRefModel = CacheUtil.getTimed(UserOrgRefModel.class, PREFIX_CODE + userId); orgRefModel = CacheUtil.getTimed(UserOrgRefModel.class, cacheKey);
if (orgRefModel != null){ if (orgRefModel != null){
return orgRefModel; return orgRefModel;
} }
@ -103,18 +96,18 @@ public class OrgUtil {
if(resultVo.isSuccess()){ if(resultVo.isSuccess()){
orgRefModel = resultVo.getData(); orgRefModel = resultVo.getData();
// 存入缓存 // 存入缓存
CacheUtil.put(PREFIX_CODE + userId, orgRefModel); CacheUtil.put(cacheKey, orgRefModel);
} }
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage(),e); log.error(e.getMessage(),e);
}finally { }finally {
// ============ 释放锁 // 释放锁
redisLockPlugins.unLock(redisLock); DistributedLockUtil.unlock(cacheKey);
} }
if(orgRefModel == null){ if(orgRefModel == null){
// 设置空变量 用于防止穿透判断 // 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(PREFIX_CODE + userId); CacheUtil.putNilFlag(cacheKey);
return null; return null;
} }
@ -176,11 +169,6 @@ public class OrgUtil {
OrgUtil.redisPlugin = redisPlugin; OrgUtil.redisPlugin = redisPlugin;
} }
@Autowired
public void setRedisLockPlugins(RedisLockPlugins redisLockPlugins) {
OrgUtil.redisLockPlugins = redisLockPlugins;
}
@Autowired @Autowired
public void setUserApi(UserApi userApi) { public void setUserApi(UserApi userApi) {
OrgUtil.userApi = userApi; OrgUtil.userApi = userApi;

@ -71,7 +71,7 @@ public class SearchHisUtil {
// 获得当前用户 // 获得当前用户
UserModel user = UserUtil.getUser(); UserModel user = UserUtil.getUser();
String cacheKey = CacheUtil.getPrefixName() + CACHE_PREFIX + user.getUsername() + ":" + key; String cacheKey = CacheUtil.getPrefixName() + CACHE_PREFIX + user.getUsername() + "::" + key;
return redisPlugin.zReverseRange(cacheKey, 0, count - 1); return redisPlugin.zReverseRange(cacheKey, 0, count - 1);
} }
@ -97,7 +97,7 @@ public class SearchHisUtil {
} }
String cacheKey = CacheUtil.getPrefixName() + CACHE_PREFIX + user.getUsername() + ":" + key; String cacheKey = CacheUtil.getPrefixName() + CACHE_PREFIX + user.getUsername() + "::" + key;
String val = values[0]; String val = values[0];
// 记录 // 记录

@ -22,9 +22,8 @@ import org.opsli.api.web.system.tenant.TenantApi;
import org.opsli.api.wrapper.system.tenant.TenantModel; import org.opsli.api.wrapper.system.tenant.TenantModel;
import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.msgs.TenantMsgFactory; import org.opsli.core.cache.pushsub.msgs.TenantMsgFactory;
import org.opsli.plugins.redis.RedisLockPlugins; import org.opsli.core.msg.CoreMsg;
import org.opsli.plugins.redis.RedisPlugin; import org.opsli.plugins.redis.RedisPlugin;
import org.opsli.plugins.redis.lock.RedisLock;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
@ -52,9 +51,6 @@ public class TenantUtil {
/** Redis插件 */ /** Redis插件 */
private static RedisPlugin redisPlugin; private static RedisPlugin redisPlugin;
/** Redis分布式锁 */
private static RedisLockPlugins redisLockPlugins;
/** 租户 Api */ /** 租户 Api */
private static TenantApi tenantApi; private static TenantApi tenantApi;
@ -65,35 +61,32 @@ public class TenantUtil {
* @return * @return
*/ */
public static TenantModel getTenant(String tenantId){ public static TenantModel getTenant(String tenantId){
// 缓存Key
String cacheKey = PREFIX_CODE + tenantId;
// 先从缓存里拿 // 先从缓存里拿
TenantModel tenantModel = CacheUtil.getTimed(TenantModel.class, PREFIX_CODE + tenantId); TenantModel tenantModel = CacheUtil.getTimed(TenantModel.class, cacheKey);
if (tenantModel != null){ if (tenantModel != null){
return tenantModel; return tenantModel;
} }
// 拿不到 -------- // 拿不到 --------
// 防止缓存穿透判断 // 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_CODE + tenantId); boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){ if(hasNilFlag){
return null; return null;
} }
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(PREFIX_CODE + tenantId)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try { try {
// 这里增加分布式锁 防止缓存击穿 // 分布式加锁
// ============ 尝试加锁 if(!DistributedLockUtil.lock(cacheKey)){
redisLock = redisLockPlugins.tryLock(redisLock); // 无法申领分布式锁
if(redisLock == null){ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null; return null;
} }
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
tenantModel = CacheUtil.getTimed(TenantModel.class, PREFIX_CODE + tenantId); tenantModel = CacheUtil.getTimed(TenantModel.class, cacheKey);
if (tenantModel != null){ if (tenantModel != null){
return tenantModel; return tenantModel;
} }
@ -103,18 +96,18 @@ public class TenantUtil {
if(resultVo.isSuccess()){ if(resultVo.isSuccess()){
tenantModel = resultVo.getData(); tenantModel = resultVo.getData();
// 存入缓存 // 存入缓存
CacheUtil.put(PREFIX_CODE + tenantId, tenantModel); CacheUtil.put(cacheKey, tenantModel);
} }
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage(),e); log.error(e.getMessage(),e);
}finally { }finally {
// ============ 释放锁 // 释放锁
redisLockPlugins.unLock(redisLock); DistributedLockUtil.unlock(cacheKey);
} }
if(tenantModel == null){ if(tenantModel == null){
// 设置空变量 用于防止穿透判断 // 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(PREFIX_CODE + tenantId); CacheUtil.putNilFlag(cacheKey);
return null; return null;
} }
@ -177,13 +170,9 @@ public class TenantUtil {
TenantUtil.redisPlugin = redisPlugin; TenantUtil.redisPlugin = redisPlugin;
} }
@Autowired
public void setRedisLockPlugins(RedisLockPlugins redisLockPlugins) {
TenantUtil.redisLockPlugins = redisLockPlugins;
}
@Autowired @Autowired
public void setTenantApi(TenantApi tenantApi) { public void setTenantApi(TenantApi tenantApi) {
TenantUtil.tenantApi = tenantApi; TenantUtil.tenantApi = tenantApi;
} }
} }

@ -74,12 +74,10 @@ public class UserTokenUtil {
private static RedisPlugin redisPlugin; private static RedisPlugin redisPlugin;
/** /**
* user Token * user Token
* @param user * @param user
* @return * @return UserTokenUtil.TokenRet
*/ */
public static ResultVo<UserTokenUtil.TokenRet> createToken(UserModel user) { public static ResultVo<UserTokenUtil.TokenRet> createToken(UserModel user) {
if (user == null) { if (user == null) {
@ -149,7 +147,7 @@ public class UserTokenUtil {
/** /**
* Token ID * Token ID
* @param token token * @param token token
* @return * @return String
*/ */
public static String getUserIdByToken(String token) { public static String getUserIdByToken(String token) {
if(StringUtils.isEmpty(token)){ if(StringUtils.isEmpty(token)){
@ -165,7 +163,7 @@ public class UserTokenUtil {
/** /**
* Token username * Token username
* @param token token * @param token token
* @return * @return String
*/ */
public static String getUserNameByToken(String token) { public static String getUserNameByToken(String token) {
if(StringUtils.isEmpty(token)){ if(StringUtils.isEmpty(token)){

@ -17,10 +17,6 @@ package org.opsli.core.utils;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.crypto.hash.Md5Hash;
@ -35,17 +31,13 @@ import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.msgs.UserMsgFactory; import org.opsli.core.cache.pushsub.msgs.UserMsgFactory;
import org.opsli.core.msg.CoreMsg; import org.opsli.core.msg.CoreMsg;
import org.opsli.core.msg.TokenMsg; import org.opsli.core.msg.TokenMsg;
import org.opsli.plugins.redis.RedisLockPlugins;
import org.opsli.plugins.redis.RedisPlugin; import org.opsli.plugins.redis.RedisPlugin;
import org.opsli.plugins.redis.lock.RedisLock;
import org.opsli.plugins.redisson.RedissonLock;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.opsli.common.constants.OrderConstants.UTIL_ORDER; import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
@ -73,9 +65,6 @@ public class UserUtil {
/** Redis插件 */ /** Redis插件 */
private static RedisPlugin redisPlugin; private static RedisPlugin redisPlugin;
/** Redisson 分布式锁 */
private static RedissonLock REDISSON_LOCK;
/** 用户Service */ /** 用户Service */
private static UserApi userApi; private static UserApi userApi;
@ -127,10 +116,8 @@ public class UserUtil {
} }
try { try {
// 分布式上锁 // 分布式加锁
boolean isLock = REDISSON_LOCK.tryLock( if(!DistributedLockUtil.lock(cacheKey)){
cacheKey, 5);
if(!isLock){
// 无法申领分布式锁 // 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage()); log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null; return null;
@ -157,11 +144,8 @@ public class UserUtil {
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
}finally { }finally {
// 是否是当前线程 // 释放锁
if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){ DistributedLockUtil.unlock(cacheKey);
// 释放锁
REDISSON_LOCK.unlock(cacheKey);
}
} }
if(userModel == null){ if(userModel == null){
@ -197,10 +181,8 @@ public class UserUtil {
} }
try { try {
// 分布式上锁 // 分布式加锁
boolean isLock = REDISSON_LOCK.tryLock( if(!DistributedLockUtil.lock(cacheKey)){
cacheKey, 5);
if(!isLock){
// 无法申领分布式锁 // 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage()); log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null; return null;
@ -222,11 +204,8 @@ public class UserUtil {
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
}finally { }finally {
// 是否是当前线程 // 释放锁
if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){ DistributedLockUtil.unlock(cacheKey);
// 释放锁
REDISSON_LOCK.unlock(cacheKey);
}
} }
if(userModel == null){ if(userModel == null){
@ -264,10 +243,8 @@ public class UserUtil {
} }
try { try {
// 分布式上锁 // 分布式加锁
boolean isLock = REDISSON_LOCK.tryLock( if(!DistributedLockUtil.lock(cacheKey)){
cacheKey, 5);
if(!isLock){
// 无法申领分布式锁 // 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage()); log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null; return null;
@ -290,11 +267,8 @@ public class UserUtil {
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
}finally { }finally {
// 是否是当前线程 // 释放锁
if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){ DistributedLockUtil.unlock(cacheKey);
// 释放锁
REDISSON_LOCK.unlock(cacheKey);
}
} }
if(CollUtil.isEmpty(roles)){ if(CollUtil.isEmpty(roles)){
@ -334,10 +308,8 @@ public class UserUtil {
} }
try { try {
// 分布式上锁 // 分布式加锁
boolean isLock = REDISSON_LOCK.tryLock( if(!DistributedLockUtil.lock(cacheKey)){
cacheKey, 5);
if(!isLock){
// 无法申领分布式锁 // 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage()); log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null; return null;
@ -360,11 +332,8 @@ public class UserUtil {
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
}finally { }finally {
// 是否是当前线程 // 释放锁
if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){ DistributedLockUtil.unlock(cacheKey);
// 释放锁
REDISSON_LOCK.unlock(cacheKey);
}
} }
if(CollUtil.isEmpty(permissions)){ if(CollUtil.isEmpty(permissions)){
@ -404,10 +373,8 @@ public class UserUtil {
try { try {
// 分布式上锁 // 分布式加锁
boolean isLock = REDISSON_LOCK.tryLock( if(!DistributedLockUtil.lock(cacheKey)){
cacheKey, 5);
if(!isLock){
// 无法申领分布式锁 // 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage()); log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null; return null;
@ -430,11 +397,8 @@ public class UserUtil {
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
}finally { }finally {
// 是否是当前线程 // 释放锁
if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){ DistributedLockUtil.unlock(cacheKey);
// 释放锁
REDISSON_LOCK.unlock(cacheKey);
}
} }
if(CollUtil.isEmpty(menus)){ if(CollUtil.isEmpty(menus)){
@ -675,14 +639,13 @@ public class UserUtil {
* @param globalProperties * @param globalProperties
*/ */
@Autowired @Autowired
public void init(GlobalProperties globalProperties, RedissonLock redissonLock){ public void init(GlobalProperties globalProperties){
if(globalProperties != null && globalProperties.getAuth() != null if(globalProperties != null && globalProperties.getAuth() != null
&& globalProperties.getAuth().getToken() != null && globalProperties.getAuth().getToken() != null
){ ){
// 获得 超级管理员 // 获得 超级管理员
UserUtil.SUPER_ADMIN = globalProperties.getAuth().getSuperAdmin(); UserUtil.SUPER_ADMIN = globalProperties.getAuth().getSuperAdmin();
} }
UserUtil.REDISSON_LOCK = redissonLock;
} }
} }

@ -18,12 +18,6 @@
"defaultValue": false, "defaultValue": false,
"description": "是否启用本地缓存 (默认不启用, 如果业务对于缓存依赖较高可启用本地缓存作为一级缓存)." "description": "是否启用本地缓存 (默认不启用, 如果业务对于缓存依赖较高可启用本地缓存作为一级缓存)."
}, },
{
"name": "spring.redis.pushsub.enable",
"type": "java.lang.Boolean",
"defaultValue": false,
"description": "开启消息订阅."
},
{ {
"name": "knife4j.basic.enable", "name": "knife4j.basic.enable",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",
@ -81,51 +75,6 @@
{
"name": "opsli.waf.enable",
"sourceType": "org.opsli.core.autoconfigure.properties.GlobalProperties$Waf",
"type": "java.lang.Boolean",
"defaultValue": false,
"description": "软防火墙是否开启."
},
{
"name": "opsli.waf.xss-filter",
"sourceType": "org.opsli.core.autoconfigure.properties.GlobalProperties$Waf",
"type": "java.lang.Boolean",
"defaultValue": false,
"description": "软防火墙 xss 过滤开启状态."
},
{
"name": "opsli.waf.sql-filter",
"sourceType": "org.opsli.core.autoconfigure.properties.GlobalProperties$Waf",
"type": "java.lang.Boolean",
"defaultValue": false,
"description": "软防火墙 sql 过滤开启状态."
},
{
"name": "opsli.waf.url-patterns",
"sourceType": "org.opsli.core.autoconfigure.properties.GlobalProperties$Waf",
"type": "java.util.Set<java.lang.String>",
"defaultValue": [
"/*"
],
"description": "软防火墙 过滤器需要过滤的路径."
},
{
"name": "opsli.waf.url-exclusion",
"sourceType": "org.opsli.core.autoconfigure.properties.GlobalProperties$Waf",
"type": "java.util.Set<java.lang.String>",
"description": "软防火墙 过滤器需要排除过滤的路径."
},
{
"name": "opsli.waf.order",
"sourceType": "org.opsli.core.autoconfigure.properties.GlobalProperties$Waf",
"type": "java.lang.Integer",
"defaultValue": 0,
"description": "软防火墙 过滤器的优先级,值越小优先级越高."
},
{ {
"name": "opsli.web.upload-path", "name": "opsli.web.upload-path",

@ -23,12 +23,12 @@ import org.opsli.core.creater.exception.CreaterException;
import org.opsli.core.creater.msg.CreaterMsg; import org.opsli.core.creater.msg.CreaterMsg;
import org.opsli.core.creater.strategy.sync.mysql.entity.FieldTypeAttribute; import org.opsli.core.creater.strategy.sync.mysql.entity.FieldTypeAttribute;
import org.opsli.core.creater.strategy.sync.mysql.enums.MySQLSyncColumnType; import org.opsli.core.creater.strategy.sync.mysql.enums.MySQLSyncColumnType;
import org.opsli.core.waf.util.SQLFilterKit;
import org.opsli.modulars.creater.column.wrapper.CreaterTableColumnModel; import org.opsli.modulars.creater.column.wrapper.CreaterTableColumnModel;
import org.opsli.modulars.creater.general.actuator.SQLActuator; import org.opsli.modulars.creater.general.actuator.SQLActuator;
import org.opsli.modulars.creater.table.service.ITableService; import org.opsli.modulars.creater.table.service.ITableService;
import org.opsli.modulars.creater.table.wrapper.CreaterTableAndColumnModel; import org.opsli.modulars.creater.table.wrapper.CreaterTableAndColumnModel;
import org.opsli.modulars.creater.table.wrapper.CreaterTableModel; import org.opsli.modulars.creater.table.wrapper.CreaterTableModel;
import org.opsli.plugins.waf.util.SQLFilterKit;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;

@ -80,12 +80,11 @@ public class RedisPluginConfig {
* *
* *
* *
* @return * @return RedisScriptCache
*/ */
@Bean @Bean
public RedisScriptCache loadScripts() { public RedisScriptCache loadScripts() {
RedisScriptCache redisScriptCache = new RedisScriptCache(); RedisScriptCache redisScriptCache = new RedisScriptCache();
RedisScriptsEnum[] scriptEnums = RedisScriptsEnum.values(); RedisScriptsEnum[] scriptEnums = RedisScriptsEnum.values();
for (RedisScriptsEnum scriptEnum : scriptEnums) { for (RedisScriptsEnum scriptEnum : scriptEnums) {
String path = scriptEnum.getPath(); String path = scriptEnum.getPath();
@ -93,47 +92,11 @@ public class RedisPluginConfig {
try { try {
ClassPathResource resource = new ClassPathResource(path); ClassPathResource resource = new ClassPathResource(path);
InputStream inputStream = resource.getInputStream(); InputStream inputStream = resource.getInputStream();
// List<String> readList = Lists.newArrayList();
// IoUtil.readLines(inputStream, StandardCharsets.UTF_8, readList);
// StringBuilder stb = new StringBuilder();
// for (String readLine : readList) {
// stb.append(readLine);
// stb.append("\n");
// }
String read = IoUtil.read(inputStream, StandardCharsets.UTF_8); String read = IoUtil.read(inputStream, StandardCharsets.UTF_8);
// 保存脚本到缓存中 // 保存脚本到缓存中
redisScriptCache.putScript(scriptEnum,read); redisScriptCache.putScript(scriptEnum,read);
}catch (Exception ignored){} }catch (Exception ignored){}
} }
/**
* Lua Java
* Lua lua IDEALua Lua
*/
// // 拿到state包下 实现了 SystemEventState 接口的,所有子类
// Set<Class<?>> clazzSet = PackageUtil.listSubClazz(RedisPluginScript.class.getPackage().getName(),
// true,
// RedisPluginScript.class
// );
//
// for (Class<?> aClass : clazzSet) {
// // 位运算 去除抽象类
// if((aClass.getModifiers() & Modifier.ABSTRACT) != 0){
// continue;
// }
//
// // 通过反射 加载所有的 脚本
// try {
// RedisPluginScript redisPluginScript = (RedisPluginScript) aClass.newInstance();
// redisScriptCache.putScript(redisPluginScript);
// } catch (Exception e) {
// log.error(RedisMsg.EXCEPTION_REFLEX.getMessage());
// }
//
// }
return redisScriptCache; return redisScriptCache;
} }

@ -0,0 +1,10 @@
{
"properties": [
{
"name": "spring.redis.pushsub.enable",
"type": "java.lang.Boolean",
"defaultValue": false,
"description": "开启消息订阅."
}
]
}

@ -0,0 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.opsli.plugins.redis.conf.RedisPluginConfig

@ -3,12 +3,14 @@ package org.opsli.plugins.redisson;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson; import org.redisson.Redisson;
import org.redisson.api.RLock; import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* @Description: Redisson * Redisson
* *
* https://github.com/yudiandemingzi/spring-boot-distributed-redisson
* @author xub * @author xub
* @date 2019/6/19 10:26 * @date 2019/6/19 10:26
*/ */
@ -17,8 +19,8 @@ public class RedissonLock {
private static final String PREFIX = "lock::"; private static final String PREFIX = "lock::";
private RedissonManager redissonManager; private RedissonManager redissonManager;
private Redisson redisson; private RedissonClient redisson;
public RedissonLock(RedissonManager redissonManager) { public RedissonLock(RedissonManager redissonManager) {
@ -93,6 +95,18 @@ public class RedissonLock {
redisson.getLock(PREFIX + lockName).unlock(); redisson.getLock(PREFIX + lockName).unlock();
} }
/**
* 线
* @param lockName
*/
public void unlockByThread(String lockName) {
// 是否是当前线程
if(this.isHeldByCurrentThread(lockName)){
// 释放锁
this.unlock(lockName);
}
}
/** /**
* 线 * 线
* @param lockName * @param lockName
@ -112,6 +126,8 @@ public class RedissonLock {
return rLock.isHeldByCurrentThread(); return rLock.isHeldByCurrentThread();
} }
// ======================
public RedissonManager getRedissonManager() { public RedissonManager getRedissonManager() {
return redissonManager; return redissonManager;
} }

@ -4,10 +4,11 @@ import cn.hutool.core.util.ClassUtil;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.opsli.plugins.redisson.entity.RedissonProperties; import org.opsli.plugins.redisson.properties.RedissonProperties;
import org.opsli.plugins.redisson.enums.RedissonType; import org.opsli.plugins.redisson.enums.RedissonType;
import org.opsli.plugins.redisson.strategy.RedissonConfigService; import org.opsli.plugins.redisson.strategy.RedissonConfigService;
import org.redisson.Redisson; import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config; import org.redisson.config.Config;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@ -16,21 +17,23 @@ import java.util.Set;
/** /**
* @Description: Redissonredisson
* *
* Redissonredisson
*
* https://github.com/yudiandemingzi/spring-boot-distributed-redisson
* @author xub * @author xub
* @date 2019/6/19 10:16 * @date 2019/6/19 10:16
*/ */
@Slf4j @Slf4j
public class RedissonManager { public class RedissonManager {
private final Redisson redisson; private final RedissonClient redisson;
public RedissonManager(RedissonProperties redissonProperties) { public RedissonManager(RedissonProperties redissonProperties) {
try { try {
//通过不同部署方式获得不同config实体 //通过不同部署方式获得不同config实体
Config config = RedissonConfigFactory.getInstance().createConfig(redissonProperties); Config config = RedissonConfigFactory.getInstance().createConfig(redissonProperties);
redisson = (Redisson) Redisson.create(config); redisson = Redisson.create(config);
} catch (Exception e) { } catch (Exception e) {
log.error("Redisson 初始化异常", e); log.error("Redisson 初始化异常", e);
throw new IllegalArgumentException("请输入正确的配置," + throw new IllegalArgumentException("请输入正确的配置," +
@ -38,7 +41,7 @@ public class RedissonManager {
} }
} }
public Redisson getRedisson() { public RedissonClient getRedisson() {
return redisson; return redisson;
} }
@ -97,7 +100,6 @@ public class RedissonManager {
Preconditions.checkNotNull(redissonProperties); Preconditions.checkNotNull(redissonProperties);
Preconditions.checkNotNull(redissonProperties.getAddress(), "redisson.lock.server.address 不能为空!"); Preconditions.checkNotNull(redissonProperties.getAddress(), "redisson.lock.server.address 不能为空!");
Preconditions.checkNotNull(redissonProperties.getType().getType(), "redisson.lock.server.password 不能为空!"); Preconditions.checkNotNull(redissonProperties.getType().getType(), "redisson.lock.server.password 不能为空!");
Preconditions.checkNotNull(redissonProperties.getDatabase(), "redisson.lock.server.database cannot 不能为空");
String connectionType = redissonProperties.getType().getType(); String connectionType = redissonProperties.getType().getType();
//声明配置上下文 //声明配置上下文
RedissonConfigService redissonConfigService = strategyMap.get(redissonProperties.getType()); RedissonConfigService redissonConfigService = strategyMap.get(redissonProperties.getType());

@ -3,7 +3,7 @@ package org.opsli.plugins.redisson.annotation;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* @Description: *
* *
* @author xub * @author xub
* @date 2019/6/19 9:22 * @date 2019/6/19 9:22
@ -17,7 +17,7 @@ public @interface DistributedLock {
/** /**
* *
*/ */
String value() default "redisson"; String value() default "opsli::redisson";
/** /**
* *

@ -13,7 +13,7 @@ import org.springframework.stereotype.Component;
/** /**
* @Description: Redisson * Redisson
* *
* @author xub * @author xub
* @date 2019/6/20 9:34 * @date 2019/6/20 9:34

@ -13,12 +13,12 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package org.opsli.core.autoconfigure.conf; package org.opsli.plugins.redisson.conf;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.opsli.plugins.redisson.RedissonLock; import org.opsli.plugins.redisson.RedissonLock;
import org.opsli.plugins.redisson.RedissonManager; import org.opsli.plugins.redisson.RedissonManager;
import org.opsli.plugins.redisson.entity.RedissonProperties; import org.opsli.plugins.redisson.properties.RedissonProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
@ -34,7 +34,7 @@ import org.springframework.core.annotation.Order;
*/ */
@Slf4j @Slf4j
@Configuration @Configuration
@ConditionalOnProperty(name = "redisson.lock.server.enable", havingValue = "true") @ConditionalOnProperty(prefix = RedissonProperties.PROP_PREFIX, name = "enable", havingValue = "true")
@EnableConfigurationProperties(RedissonProperties.class) @EnableConfigurationProperties(RedissonProperties.class)
public class RedissonConfig { public class RedissonConfig {

@ -2,8 +2,9 @@ package org.opsli.plugins.redisson.constant;
/** /**
* URL
*
* @author xub * @author xub
* @Description: URL
* @date 2019/6/19 9:09 * @date 2019/6/19 9:09
*/ */
public enum GlobalConstant { public enum GlobalConstant {
@ -11,19 +12,19 @@ public enum GlobalConstant {
/** 前缀 */ /** 前缀 */
REDIS_CONNECTION_PREFIX("redis://", "Redis地址配置前缀"); REDIS_CONNECTION_PREFIX("redis://", "Redis地址配置前缀");
private final String constant_value; private final String constantValue;
private final String constant_desc; private final String constantDesc;
GlobalConstant(String constant_value, String constant_desc) { GlobalConstant(String constantValue, String constantDesc) {
this.constant_value = constant_value; this.constantValue = constantValue;
this.constant_desc = constant_desc; this.constantDesc = constantDesc;
} }
public String getConstant_value() { public String getConstantValue() {
return constant_value; return constantValue;
} }
public String getConstant_desc() { public String getConstantDesc() {
return constant_desc; return constantDesc;
} }
} }

@ -17,11 +17,10 @@ package org.opsli.plugins.redisson.enums;
/** /**
* @BelongsProject: opsli-boot * Redisson
* @BelongsPackage: org.opsli.common.enums *
* @Author: Parker * @author : Parker
* @CreateTime: 2020-09-17 23:40 * @date 2020-09-17 23:40
* @Description: Redisson
*/ */
public enum RedissonType { public enum RedissonType {
@ -29,7 +28,7 @@ public enum RedissonType {
STANDALONE("standalone", "单节点部署方式"), STANDALONE("standalone", "单节点部署方式"),
SENTINEL("sentinel", "哨兵部署方式"), SENTINEL("sentinel", "哨兵部署方式"),
CLUSTER("cluster", "集群方式"), CLUSTER("cluster", "集群方式"),
MASTER_SLAVE("master_slave", "主从部署方式"); MASTER_SLAVE("master_slave", "主从部署方式"),
; ;

@ -1,4 +1,4 @@
package org.opsli.plugins.redisson.entity; package org.opsli.plugins.redisson.properties;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@ -7,17 +7,19 @@ import org.opsli.plugins.redisson.enums.RedissonType;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
* @Description: redis * redis
* *
* @author xub * @author xub
* @date 2019/6/19 9:35 * @date 2019/6/19 9:35
*/ */
@ConfigurationProperties(prefix = "redisson.lock.server") @ConfigurationProperties(prefix = RedissonProperties.PROP_PREFIX)
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class RedissonProperties { public class RedissonProperties {
public static final String PROP_PREFIX = "redisson.lock.server";
/** /**
* *
*/ */

@ -1,12 +1,12 @@
package org.opsli.plugins.redisson.strategy; package org.opsli.plugins.redisson.strategy;
import org.opsli.plugins.redisson.entity.RedissonProperties; import org.opsli.plugins.redisson.properties.RedissonProperties;
import org.opsli.plugins.redisson.enums.RedissonType; import org.opsli.plugins.redisson.enums.RedissonType;
import org.redisson.config.Config; import org.redisson.config.Config;
/** /**
* @Description: Redisson * Redisson
* *
* @author xub * @author xub
* @date 2019/6/20 3:35 * @date 2019/6/20 3:35

@ -4,13 +4,13 @@ package org.opsli.plugins.redisson.strategy.impl;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.opsli.plugins.redisson.constant.GlobalConstant; import org.opsli.plugins.redisson.constant.GlobalConstant;
import org.opsli.plugins.redisson.entity.RedissonProperties; import org.opsli.plugins.redisson.properties.RedissonProperties;
import org.opsli.plugins.redisson.enums.RedissonType; import org.opsli.plugins.redisson.enums.RedissonType;
import org.opsli.plugins.redisson.strategy.RedissonConfigService; import org.opsli.plugins.redisson.strategy.RedissonConfigService;
import org.redisson.config.Config; import org.redisson.config.Config;
/** /**
* @Description: Redisson * Redisson
* *
* cluster6(333sharding3) * cluster6(333sharding3)
* : 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 * : 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
@ -36,7 +36,7 @@ public class ClusterConfigImpl implements RedissonConfigService {
//设置cluster节点的服务IP和端口 //设置cluster节点的服务IP和端口
for (String addrToken : addrTokens) { for (String addrToken : addrTokens) {
config.useClusterServers() config.useClusterServers()
.addNodeAddress(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + addrToken); .addNodeAddress(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstantValue() + addrToken);
if (StringUtils.isNotBlank(password)) { if (StringUtils.isNotBlank(password)) {
config.useClusterServers().setPassword(password); config.useClusterServers().setPassword(password);
} }

@ -6,16 +6,15 @@ import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.opsli.plugins.redisson.constant.GlobalConstant; import org.opsli.plugins.redisson.constant.GlobalConstant;
import org.opsli.plugins.redisson.entity.RedissonProperties; import org.opsli.plugins.redisson.properties.RedissonProperties;
import org.opsli.plugins.redisson.enums.RedissonType; import org.opsli.plugins.redisson.enums.RedissonType;
import org.opsli.plugins.redisson.strategy.RedissonConfigService; import org.opsli.plugins.redisson.strategy.RedissonConfigService;
import org.redisson.config.Config; import org.redisson.config.Config;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* @Description: Redisson * Redisson
* : ,, * : ,,
* : 127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381 * : 127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381
* @author xub * @author xub
@ -48,7 +47,7 @@ public class MasterslaveConfigImpl implements RedissonConfigService {
//设置从节点,移除第一个节点,默认第一个为主节点 //设置从节点,移除第一个节点,默认第一个为主节点
List<String> slaveList = Lists.newArrayList(); List<String> slaveList = Lists.newArrayList();
for (String addrToken : addrTokens) { for (String addrToken : addrTokens) {
slaveList.add(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + addrToken); slaveList.add(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstantValue() + addrToken);
} }
slaveList.remove(0); slaveList.remove(0);

@ -4,14 +4,14 @@ package org.opsli.plugins.redisson.strategy.impl;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.opsli.plugins.redisson.constant.GlobalConstant; import org.opsli.plugins.redisson.constant.GlobalConstant;
import org.opsli.plugins.redisson.entity.RedissonProperties; import org.opsli.plugins.redisson.properties.RedissonProperties;
import org.opsli.plugins.redisson.enums.RedissonType; import org.opsli.plugins.redisson.enums.RedissonType;
import org.opsli.plugins.redisson.strategy.RedissonConfigService; import org.opsli.plugins.redisson.strategy.RedissonConfigService;
import org.redisson.config.Config; import org.redisson.config.Config;
/** /**
* @Description: Redis * Redis
* *
* @author xub * @author xub
* @date 2019/6/19 9:17 * @date 2019/6/19 9:17
@ -41,7 +41,7 @@ public class SentinelConfigImpl implements RedissonConfigService {
} }
//设置sentinel节点的服务IP和端口 //设置sentinel节点的服务IP和端口
for (int i = 1; i < addrTokens.length; i++) { for (int i = 1; i < addrTokens.length; i++) {
config.useSentinelServers().addSentinelAddress(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + addrTokens[i]); config.useSentinelServers().addSentinelAddress(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstantValue() + addrTokens[i]);
} }
log.info("初始化[哨兵部署]方式Config,redisAddress:" + address); log.info("初始化[哨兵部署]方式Config,redisAddress:" + address);
} catch (Exception e) { } catch (Exception e) {

@ -4,13 +4,13 @@ package org.opsli.plugins.redisson.strategy.impl;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.opsli.plugins.redisson.constant.GlobalConstant; import org.opsli.plugins.redisson.constant.GlobalConstant;
import org.opsli.plugins.redisson.entity.RedissonProperties; import org.opsli.plugins.redisson.properties.RedissonProperties;
import org.opsli.plugins.redisson.enums.RedissonType; import org.opsli.plugins.redisson.enums.RedissonType;
import org.opsli.plugins.redisson.strategy.RedissonConfigService; import org.opsli.plugins.redisson.strategy.RedissonConfigService;
import org.redisson.config.Config; import org.redisson.config.Config;
/** /**
* @Description: Redisson * Redisson
* *
* @author xub * @author xub
* @date 2019/6/19 10:04 * @date 2019/6/19 10:04
@ -31,7 +31,7 @@ public class StandaloneConfigImpl implements RedissonConfigService {
String address = redissonProperties.getAddress(); String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword(); String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase(); int database = redissonProperties.getDatabase();
String redisAddr = GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + address; String redisAddr = GlobalConstant.REDIS_CONNECTION_PREFIX.getConstantValue() + address;
config.useSingleServer().setAddress(redisAddr); config.useSingleServer().setAddress(redisAddr);
config.useSingleServer().setDatabase(database); config.useSingleServer().setDatabase(database);
//密码可以为空 //密码可以为空

@ -2,32 +2,32 @@
"properties": [ "properties": [
{ {
"name": "redisson.lock.server.enable", "name": "redisson.lock.server.enable",
"sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties", "sourceType": "org.opsli.plugins.redisson.properties.RedissonProperties",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",
"defaultValue": false, "defaultValue": false,
"description": "redissonLock 是否启用." "description": "redissonLock 是否启用."
}, },
{ {
"name": "redisson.lock.server.address", "name": "redisson.lock.server.address",
"sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties", "sourceType": "org.opsli.plugins.redisson.properties.RedissonProperties",
"type": "java.lang.String", "type": "java.lang.String",
"defaultValue": "127.0.0.1:6379", "defaultValue": "127.0.0.1:6379",
"description": "redis主机地址ipport有多个用半角逗号分隔." "description": "redis主机地址ipport有多个用半角逗号分隔."
}, },
{ {
"name": "redisson.lock.server.type", "name": "redisson.lock.server.type",
"sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties", "sourceType": "org.opsli.plugins.redisson.properties.RedissonProperties",
"description": "连接类型支持standalone-单机节点sentinel-哨兵cluster-集群masterslave-主从." "description": "连接类型支持standalone-单机节点sentinel-哨兵cluster-集群masterslave-主从."
}, },
{ {
"name": "redisson.lock.server.password", "name": "redisson.lock.server.password",
"sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties", "sourceType": "org.opsli.plugins.redisson.properties.RedissonProperties",
"type": "java.lang.String", "type": "java.lang.String",
"description": "redis 连接密码." "description": "redis 连接密码."
}, },
{ {
"name": "redisson.lock.server.database", "name": "redisson.lock.server.database",
"sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties", "sourceType": "org.opsli.plugins.redisson.properties.RedissonProperties",
"type": "java.lang.Integer", "type": "java.lang.Integer",
"defaultValue": 0, "defaultValue": 0,
"description": "选取那个数据库 ." "description": "选取那个数据库 ."

@ -0,0 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.opsli.plugins.redisson.conf.RedissonConfig

@ -21,6 +21,7 @@
<module>opsli-plugins-ehcache</module> <module>opsli-plugins-ehcache</module>
<module>opsli-plugins-excel</module> <module>opsli-plugins-excel</module>
<module>opsli-plugins-redisson</module> <module>opsli-plugins-redisson</module>
<module>opsli-plugins-waf</module>
</modules> </modules>
<dependencyManagement> <dependencyManagement>
@ -43,4 +44,4 @@
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

Loading…
Cancel
Save