本地EhCache缓存 热插拔 一键式开启本地缓存

v1.4.1
Parker 4 years ago
parent 468f326aa3
commit 335119f3cc

@ -13,6 +13,6 @@ public interface CacheConstants {
String HOT_DATA = "hotData";
/** 系统常量 */
String SYSTEM_DATA = "systemData";
String EDEN_DATA = "edenData";
}

@ -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;

@ -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:
*
* keyRedis
* 使expire()idletime
*
* bigkey()
* string10KBhashlistsetzset5000
*
*
*/
@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> V get(String key, Class<V> vClass){
return CacheUtil.get(CacheConstants.HOT_DATA,key,vClass,true);
}
/**
*
* Key
* Key opsli:hotData:ahdjksahjkd1
*
* @param key
* @param vClass
* @return
*/
public static <V> V getByKeyOriginal(String key, Class<V> vClass){
return CacheUtil.get(CacheConstants.HOT_DATA,key,vClass,false);
}
private static <V> V get(String cacheName, String key, Class<V> 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;
}
/**
*
* RedisEhCache
* 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;
}
}

@ -15,8 +15,8 @@ public enum PushSubType {
/** 热点数据 */
HOT_DATA,
/** 系统数据 */
SYSTEM_DATA
/** 永久数据 */
EDEN_DATA
;

@ -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);
}
}

@ -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);
}
}

@ -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 {

@ -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;
}
}

@ -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> V get(String cacheName, String key, Class<V> 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;
}

@ -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

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
<!-- http://www.ehcache.org/documentation/3.8/xml.html -->
<!--指定缓存持久化目录-->
<persistence directory="${java.io.tmpdir}/opsli-ehcache-data"/>
@ -23,16 +23,9 @@
<cache alias="hotData" uses-template="opsliDefaults">
<!--缓存到期配置-->
<expiry>
<ttl unit="minutes">10</ttl> <!-- 使用 TTL(time to leave)策略 -->
<!-- 只允许配秒 -->
<ttl unit="seconds">60000</ttl>
</expiry>
</cache>
<!-- 系统数据 -->
<cache alias="systemData" uses-template="opsliDefaults">
<!--缓存到期配置-->
<expiry>
<ttl unit="minutes">600</ttl> <!-- 使用 TTL(time to leave)策略 -->
<!-- <tti unit="minutes">600</tti> &lt;!&ndash; 使用 TTI(time to idle) 策略 &ndash;&gt;-->
</expiry>
</cache>
</config>
Loading…
Cancel
Save