From 335119f3ccdebd45ea3fda7ef22e74cdcd26edda Mon Sep 17 00:00:00 2001 From: Parker Date: Thu, 17 Sep 2020 11:51:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=AC=E5=9C=B0EhCache=E7=BC=93=E5=AD=98=20?= =?UTF-8?q?=E7=83=AD=E6=8F=92=E6=8B=94=20=E4=B8=80=E9=94=AE=E5=BC=8F?= =?UTF-8?q?=E5=BC=80=E5=90=AF=E6=9C=AC=E5=9C=B0=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constants/CacheConstants.java | 2 +- .../org/opsli/core/aspect/CacheDataAop.java | 12 +- .../org/opsli/core/cache/local/CacheUtil.java | 170 +++++++++++++++++- .../core/cache/pushsub/enums/PushSubType.java | 4 +- ...mDataHandler.java => EdenDataHandler.java} | 31 +--- .../cache/pushsub/handler/HotDataHandler.java | 25 +-- .../receiver/RedisPushSubReceiver.java | 2 +- .../plugins/cache/conf/EhCacheConfig.java | 2 + .../opsli/plugins/cache/msg/EhCacheMsg.java | 41 +++++ .../cache/service/EhCachePluginImpl.java | 21 ++- opsli-web/src/main/resources/application.yaml | 10 +- .../main/resources/config/ehcache-opsli.xml | 13 +- 12 files changed, 252 insertions(+), 81 deletions(-) rename opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/{SystemDataHandler.java => EdenDataHandler.java} (50%) create mode 100644 opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/msg/EhCacheMsg.java diff --git a/opsli-common/src/main/java/org/opsli/common/constants/CacheConstants.java b/opsli-common/src/main/java/org/opsli/common/constants/CacheConstants.java index 3d6526d..ddeff18 100644 --- a/opsli-common/src/main/java/org/opsli/common/constants/CacheConstants.java +++ b/opsli-common/src/main/java/org/opsli/common/constants/CacheConstants.java @@ -13,6 +13,6 @@ public interface CacheConstants { String HOT_DATA = "hotData"; /** 系统常量 */ - String SYSTEM_DATA = "systemData"; + String EDEN_DATA = "edenData"; } diff --git a/opsli-core/src/main/java/org/opsli/core/aspect/CacheDataAop.java b/opsli-core/src/main/java/org/opsli/core/aspect/CacheDataAop.java index 7e7e77d..16f8d00 100644 --- a/opsli-core/src/main/java/org/opsli/core/aspect/CacheDataAop.java +++ b/opsli-core/src/main/java/org/opsli/core/aspect/CacheDataAop.java @@ -71,9 +71,9 @@ public class CacheDataAop { type = PushSubType.HOT_DATA; } // 系统数据 - else if(CacheConstants.SYSTEM_DATA.equals(aCache.name())){ - keyBuf.append(CacheConstants.SYSTEM_DATA).append(":"); - type = PushSubType.SYSTEM_DATA; + else if(CacheConstants.EDEN_DATA.equals(aCache.name())){ + keyBuf.append(CacheConstants.EDEN_DATA).append(":"); + type = PushSubType.EDEN_DATA; } else { // 如果都不是 则直接退出 不走缓存 return returnValue; @@ -123,9 +123,9 @@ public class CacheDataAop { type = PushSubType.HOT_DATA; } // 系统数据 - else if(CacheConstants.SYSTEM_DATA.equals(aCache.name())){ - keyBuf.append(CacheConstants.SYSTEM_DATA).append(":"); - type = PushSubType.SYSTEM_DATA; + else if(CacheConstants.EDEN_DATA.equals(aCache.name())){ + keyBuf.append(CacheConstants.EDEN_DATA).append(":"); + type = PushSubType.EDEN_DATA; } else { // 如果都不是 则直接退出 不走缓存 return returnValue; diff --git a/opsli-core/src/main/java/org/opsli/core/cache/local/CacheUtil.java b/opsli-core/src/main/java/org/opsli/core/cache/local/CacheUtil.java index a412ae7..023ca7c 100644 --- a/opsli-core/src/main/java/org/opsli/core/cache/local/CacheUtil.java +++ b/opsli-core/src/main/java/org/opsli/core/cache/local/CacheUtil.java @@ -1,13 +1,20 @@ package org.opsli.core.cache.local; +import cn.hutool.core.util.XmlUtil; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.StringUtils; import org.opsli.common.constants.CacheConstants; import org.opsli.core.aspect.CacheDataAop; import org.opsli.plugins.cache.EhCachePlugin; import org.opsli.plugins.redis.RedisPlugin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; /** @@ -16,26 +23,58 @@ import org.springframework.stereotype.Component; * @Author: Parker * @CreateTime: 2020-09-16 16:20 * @Description: 本地 缓存接口 + * + * 一、控制key的生命周期,Redis不是垃圾桶(缓存不是垃圾桶) + * 建议使用expire设置过期时间(条件允许可以打散过期时间,防止集中过期),不过期的数据重点关注idletime。 + * + * 二、【强制】:拒绝bigkey(防止网卡流量、慢查询) + * string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。 + * + * */ @Slf4j @Component public class CacheUtil { + /** 热点数据缓存时间 秒 */ + private static int ttlHotData; /** Redis插件 */ private static RedisPlugin redisPlugin; /** EhCache插件 */ private static EhCachePlugin ehCachePlugin; + static { + // 读取配置信息 + CacheUtil.readPropertyXML(); + } + + /** + * 取缓存 + * Key 程序自处理 + * 比如:jksahdjh1j1hjk1 + * + * @param key 键 + * @param vClass 转换类型 + * @return + */ public static V get(String key, Class vClass){ return CacheUtil.get(CacheConstants.HOT_DATA,key,vClass,true); } + /** + * 取缓存 + * Key 程序不处理 + * 比如:源Key opsli:hotData:ahdjksahjkd1 + * + * @param key 键 + * @param vClass 转换类型 + * @return + */ public static V getByKeyOriginal(String key, Class vClass){ return CacheUtil.get(CacheConstants.HOT_DATA,key,vClass,false); } - - private static V get(String cacheName, String key, Class vClass,boolean keyFlag){ + String KeyOriginal = key; // 自动处理 key if(keyFlag){ StringBuilder keyBuf = new StringBuilder(CacheDataAop.PREFIX_NAME); @@ -53,6 +92,8 @@ public class CacheUtil { }else{ jsonObject = (JSONObject) redisPlugin.get(key); if(jsonObject != null){ + // 存入EhCache + ehCachePlugin.put(CacheConstants.HOT_DATA, KeyOriginal, jsonObject); v = jsonObject.toJavaObject(vClass); } } @@ -62,8 +103,130 @@ public class CacheUtil { return v; } + /** + * 存缓存 + * 默认取配置文件中缓存失效时间 + * 注意:不是永久缓存 + * @param key 键 + * @param value 值 + * @return + */ + public static boolean put(String key, Object value) { + return CacheUtil.put(key, value, null); + } + private static boolean put(String key, Object value,Integer timeout) { + boolean ret = false; + try { + // 如果缓存失效时间设置为空 则默认使用系统配置时间 + // 对于Redis缓存定位,为远程缓存同步库 当EhCache缓存失效时,Redis可以起到抗一波的作用 + // 所以,为了防止缓存雪崩 让Redis的失效时间 = EhCache热数据失效时间*1.2 ~ 2 倍之间随机 + if(timeout == null){ + timeout = RandomUtils.nextInt( + Double.valueOf(String.valueOf(ttlHotData * 1.2)).intValue(), + Double.valueOf(String.valueOf(ttlHotData * 2)).intValue()); + } + // 存入EhCache + ehCachePlugin.put(CacheConstants.HOT_DATA,key, value); + // 存入Redis + redisPlugin.put(key, value, timeout); + ret = true; + }catch (Exception e){ + log.error(e.getMessage(),e); + } + return ret; + } + + /** + * 存缓存 + * 注:这里是存入Redis永久代,本地EhCache做临时缓存 + * Redis不是垃圾桶 谨用 永久缓存 + * + * @param key + * @param value + * @return + */ + @Deprecated + public static boolean putByEden(String key, Object value) { + boolean ret = false; + try { + // 存入EhCache + ehCachePlugin.put(CacheConstants.EDEN_DATA,key, value); + // 存入Redis + redisPlugin.put(key, value); + ret = true; + }catch (Exception e){ + log.error(e.getMessage(),e); + } + return ret; + } + + /** + * 删缓存 + * + * @param key + * @return + */ + public static boolean del(String key) { + boolean ret = false; + try { + // 删除 EhCache + ehCachePlugin.delete(CacheConstants.HOT_DATA,key); + // 删除 Redis + redisPlugin.del(key); + ret = true; + }catch (Exception e){ + log.error(e.getMessage(),e); + } + return ret; + } + + // ==================================================================== + + /** + * 读配置文件 + */ + private static void readPropertyXML(){ + Document document = XmlUtil.readXML("config/ehcache-opsli.xml"); + NodeList nodeList = document.getElementsByTagName("cache"); + if(nodeList != null){ + for (int i = 0; i < nodeList.getLength(); i++) { + Node item = nodeList.item(i); + NamedNodeMap attributes = item.getAttributes(); + if(attributes == null){ + continue; + } + Node alias = attributes.getNamedItem("alias"); + if("hotData".equals(alias.getNodeValue())){ + NodeList childNodes = item.getChildNodes(); + if(childNodes != null){ + for (int j = 0; j < childNodes.getLength(); j++) { + if("expiry".equals(childNodes.item(j).getNodeName())){ + NodeList expiryNodes = childNodes.item(j).getChildNodes(); + if(expiryNodes != null){ + for (int k = 0; k < expiryNodes.getLength(); k++) { + if("ttl".equals(expiryNodes.item(k).getNodeName())){ + Node ttlNode = expiryNodes.item(k); + Node ttlValue = ttlNode.getFirstChild(); + // 默认 60000秒 6小时 + String ttl = "60000"; + if(StringUtils.isNotEmpty(ttlValue.getNodeValue())){ + ttl = ttlValue.getNodeValue(); + } + ttlHotData = Integer.parseInt(ttl); + break; + } + } + } + break; + } + } + } + break; + } + } + } + } - // ================================ @Autowired public void setRedisPlugin(RedisPlugin redisPlugin) { CacheUtil.redisPlugin = redisPlugin; @@ -73,4 +236,5 @@ public class CacheUtil { public void setEhCachePlugin(EhCachePlugin ehCachePlugin) { CacheUtil.ehCachePlugin = ehCachePlugin; } + } diff --git a/opsli-core/src/main/java/org/opsli/core/cache/pushsub/enums/PushSubType.java b/opsli-core/src/main/java/org/opsli/core/cache/pushsub/enums/PushSubType.java index eccd782..3a92b90 100644 --- a/opsli-core/src/main/java/org/opsli/core/cache/pushsub/enums/PushSubType.java +++ b/opsli-core/src/main/java/org/opsli/core/cache/pushsub/enums/PushSubType.java @@ -15,8 +15,8 @@ public enum PushSubType { /** 热点数据 */ HOT_DATA, - /** 系统数据 */ - SYSTEM_DATA + /** 永久数据 */ + EDEN_DATA ; diff --git a/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/SystemDataHandler.java b/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/EdenDataHandler.java similarity index 50% rename from opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/SystemDataHandler.java rename to opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/EdenDataHandler.java index 5eba0f7..690095b 100644 --- a/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/SystemDataHandler.java +++ b/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/EdenDataHandler.java @@ -2,37 +2,24 @@ package org.opsli.core.cache.pushsub.handler; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; -import org.opsli.common.constants.CacheConstants; +import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.cache.pushsub.enums.CacheType; import org.opsli.core.cache.pushsub.enums.MsgArgsType; import org.opsli.core.cache.pushsub.enums.PushSubType; -import org.opsli.plugins.cache.EhCachePlugin; -import org.opsli.plugins.redis.RedisPlugin; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; /** * @BelongsProject: opsli-boot * @BelongsPackage: org.opsli.core.cache.pushsub.handler * @Author: Parker * @CreateTime: 2020-09-15 16:24 - * @Description: 系统数据处理 + * @Description: 永久数据处理 */ @Slf4j -public class SystemDataHandler implements RedisPushSubHandler{ - - /** 热点数据缓存时间 */ - @Value("${cache.ttl-system-data}") - private int ttlSystemData; - - @Autowired - private RedisPlugin redisPlugin; - @Autowired - private EhCachePlugin cachePlugin; +public class EdenDataHandler implements RedisPushSubHandler{ @Override public PushSubType getType() { - return PushSubType.SYSTEM_DATA; + return PushSubType.EDEN_DATA; } @Override @@ -43,17 +30,11 @@ public class SystemDataHandler implements RedisPushSubHandler{ // 缓存更新 if(CacheType.UPDATE == type){ - // 存入EhCache - cachePlugin.put(CacheConstants.SYSTEM_DATA,key, value); - // 存入Redis - redisPlugin.put(key, value, ttlSystemData); + CacheUtil.putByEden(key, value); } // 缓存删除 else if(CacheType.DELETE == type){ - // 存入EhCache - cachePlugin.delete(CacheConstants.SYSTEM_DATA,key); - // 存入Redis - redisPlugin.del(key); + CacheUtil.del(key); } } diff --git a/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/HotDataHandler.java b/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/HotDataHandler.java index dc15db3..c3d40d0 100644 --- a/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/HotDataHandler.java +++ b/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/HotDataHandler.java @@ -2,14 +2,10 @@ package org.opsli.core.cache.pushsub.handler; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; -import org.opsli.common.constants.CacheConstants; +import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.cache.pushsub.enums.CacheType; import org.opsli.core.cache.pushsub.enums.MsgArgsType; import org.opsli.core.cache.pushsub.enums.PushSubType; -import org.opsli.plugins.cache.EhCachePlugin; -import org.opsli.plugins.redis.RedisPlugin; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; /** * @BelongsProject: opsli-boot @@ -21,15 +17,6 @@ import org.springframework.beans.factory.annotation.Value; @Slf4j public class HotDataHandler implements RedisPushSubHandler{ - /** 热点数据缓存时间 */ - @Value("${cache.ttl-hot-data}") - private int ttlHotData; - - @Autowired - private RedisPlugin redisPlugin; - @Autowired - private EhCachePlugin cachePlugin; - @Override public PushSubType getType() { return PushSubType.HOT_DATA; @@ -43,17 +30,11 @@ public class HotDataHandler implements RedisPushSubHandler{ // 缓存更新 if(CacheType.UPDATE == type){ - // 存入EhCache - cachePlugin.put(CacheConstants.HOT_DATA,key, value); - // 存入Redis - redisPlugin.put(key, value, ttlHotData); + CacheUtil.put(key, value); } // 缓存删除 else if(CacheType.DELETE == type){ - // 存入EhCache - cachePlugin.delete(CacheConstants.HOT_DATA,key); - // 存入Redis - redisPlugin.del(key); + CacheUtil.del(key); } } diff --git a/opsli-core/src/main/java/org/opsli/core/cache/pushsub/receiver/RedisPushSubReceiver.java b/opsli-core/src/main/java/org/opsli/core/cache/pushsub/receiver/RedisPushSubReceiver.java index 55b5444..f94e89f 100644 --- a/opsli-core/src/main/java/org/opsli/core/cache/pushsub/receiver/RedisPushSubReceiver.java +++ b/opsli-core/src/main/java/org/opsli/core/cache/pushsub/receiver/RedisPushSubReceiver.java @@ -74,7 +74,7 @@ public class RedisPushSubReceiver extends BaseReceiver { HANDLER_MAP.put(handler.getType(),handler); //将new出的对象放入Spring容器中 - defaultListableBeanFactory.registerSingleton("redisPushSubHandler"+count,obj); + defaultListableBeanFactory.registerSingleton("redisPushSubHandler"+count, obj); //自动注入依赖 beanFactory.autowireBean(obj); diff --git a/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/conf/EhCacheConfig.java b/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/conf/EhCacheConfig.java index e283fd8..1b21434 100644 --- a/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/conf/EhCacheConfig.java +++ b/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/conf/EhCacheConfig.java @@ -1,5 +1,6 @@ package org.opsli.plugins.cache.conf; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Configuration; @@ -12,6 +13,7 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @EnableCaching +@ConditionalOnProperty(name = "spring.cache.enable", havingValue = "true") public class EhCacheConfig { diff --git a/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/msg/EhCacheMsg.java b/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/msg/EhCacheMsg.java new file mode 100644 index 0000000..2fd7f94 --- /dev/null +++ b/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/msg/EhCacheMsg.java @@ -0,0 +1,41 @@ +package org.opsli.plugins.cache.msg; + +import org.opsli.common.base.msg.BaseMsg; + +/** + * @BelongsProject: opsli-boot + * @BelongsPackage: org.opsli.plugins.mail.msg + * @Author: Parker + * @CreateTime: 2020-09-13 19:54 + * @Description: 邮件消息 + */ +public enum EhCacheMsg implements BaseMsg { + + /** 缓存未开启 */ + EXCEPTION_ENABLE(90001,"本地缓存未开启!"), + EXCEPTION_PUT(90001,"添加缓存失败"), + EXCEPTION_GET(90001,"获取缓存数据失败"), + EXCEPTION_DEL(90001,"删除缓存数据失败"), + + + ; + + + private int code; + private String message; + + EhCacheMsg(int code, String message){ + this.code = code; + this.message = message; + } + + @Override + public Integer getCode() { + return this.code; + } + + @Override + public String getMessage() { + return this.message; + } +} diff --git a/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/service/EhCachePluginImpl.java b/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/service/EhCachePluginImpl.java index 1afbaa6..60e3f3d 100644 --- a/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/service/EhCachePluginImpl.java +++ b/opsli-plugins/opsli-plugins-ehcache/src/main/java/org/opsli/plugins/cache/service/EhCachePluginImpl.java @@ -1,6 +1,7 @@ package org.opsli.plugins.cache.service; import lombok.extern.slf4j.Slf4j; +import org.opsli.plugins.cache.msg.EhCacheMsg; import org.springframework.cache.Cache; import org.opsli.plugins.cache.EhCachePlugin; import org.springframework.beans.factory.annotation.Autowired; @@ -24,6 +25,9 @@ public class EhCachePluginImpl implements EhCachePlugin { @Override public boolean put(String cacheName, String key, Object value) { + if(cacheManager == null){ + return false; + } boolean ret = false; try { Cache cache = cacheManager.getCache(cacheName); @@ -32,39 +36,48 @@ public class EhCachePluginImpl implements EhCachePlugin { ret = true; } } catch (Exception e) { - log.error("添加缓存失败:{}",e.getMessage()); + log.error(EhCacheMsg.EXCEPTION_PUT.getMessage()+":{}",e.getMessage()); } return ret; } @Override public Object get(String cacheName, String key) { + if(cacheManager == null){ + return null; + } try { Cache cache = cacheManager.getCache(cacheName); if(cache != null){ return cache.get(key); } } catch (Exception e) { - log.error("获取缓存数据失败:{}",e.getMessage()); + log.error(EhCacheMsg.EXCEPTION_GET.getMessage()+":{}",e.getMessage()); } return null; } @Override public V get(String cacheName, String key, Class vClass) { + if(cacheManager == null){ + return null; + } try { Cache cache = cacheManager.getCache(cacheName); if(cache != null){ return cache.get(key,vClass); } } catch (Exception e) { - log.error("获取缓存数据失败:{}",e.getMessage()); + log.error(EhCacheMsg.EXCEPTION_GET.getMessage()+":{}", e.getMessage()); } return null; } @Override public boolean delete(String cacheName, String key) { + if(cacheManager == null){ + return false; + } boolean ret = false; try { Cache cache = cacheManager.getCache(cacheName); @@ -73,7 +86,7 @@ public class EhCachePluginImpl implements EhCachePlugin { ret = true; } } catch (Exception e) { - log.error("删除缓存数据失败:{}",e.getMessage()); + log.error(EhCacheMsg.EXCEPTION_DEL.getMessage()+":{}", e.getMessage()); } return ret; } diff --git a/opsli-web/src/main/resources/application.yaml b/opsli-web/src/main/resources/application.yaml index cd0aea1..a1ca692 100644 --- a/opsli-web/src/main/resources/application.yaml +++ b/opsli-web/src/main/resources/application.yaml @@ -56,6 +56,9 @@ spring: # EhCache 配置 cache: + # 开启 是否启用本地缓存 + enable: true + # 加载配置文件 jcache: config: classpath:config/ehcache-opsli.xml #redis 配置 @@ -132,10 +135,3 @@ mybatis-plus: call-setters-on-nulls: true # 打印SQL 开发测试使用 生产关闭 *** #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - -# 缓存设置 -cache: - # 热点数据 缓存时间 600秒 10分钟 - ttl-hot-data: 600 - # 系统数据 缓存时间 60000秒 6小时 - ttl-system-data: 60000 \ No newline at end of file diff --git a/opsli-web/src/main/resources/config/ehcache-opsli.xml b/opsli-web/src/main/resources/config/ehcache-opsli.xml index 0409436..89204c6 100644 --- a/opsli-web/src/main/resources/config/ehcache-opsli.xml +++ b/opsli-web/src/main/resources/config/ehcache-opsli.xml @@ -1,8 +1,8 @@ + - @@ -23,16 +23,9 @@ - 10 + + 60000 - - - - - 600 - - - \ No newline at end of file