1、Springboot开启缓存,并引入ehcache依赖。
<!-- 开启cache缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- 整合ehcache缓存 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
3、创建ehcache.xml配置文件
具体配置如下:关于配置参数说明,可以参考:XXXXXXXXXXXXXXXXXXXXX(文章整理中)
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd">
<!--timeToIdleSeconds 当缓存闲置n秒后销毁 -->
<!--timeToLiveSeconds 当缓存存活n秒后销毁 -->
<!-- 缓存配置
name:缓存名称。
maxElementsInMemory:缓存最大个数。
maxEntriesLocalHeap:堆内存中最大缓存对象数,0没有限制
maxEntriesLocalDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
maxElementsOnDisk:硬盘最大缓存个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是 LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。 -->
<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir/Tmp_EhCache" />
<!-- 默认缓存 -->
<defaultCache
eternal="false"
maxElementsInMemory="1000"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="10000000"
maxElementsOnDisk="10000000"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
diskExpiryThreadIntervalSeconds="120"
overflowToDisk="false"
diskPersistent="false"
memoryStoreEvictionPolicy="LRU" >
<!-- <persistence strategy="localTempSwap" /> -->
</defaultCache>
<!-- cache设置,可配置多个cache,根据name可以初始化多个ehcache缓存 -->
<cache
name="wonddream_ehcache"
eternal="false"
maxElementsInMemory="1000"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="10000000"
maxElementsOnDisk="10000000"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
diskExpiryThreadIntervalSeconds="120"
overflowToDisk="false"
diskPersistent="false"
memoryStoreEvictionPolicy="LRU" >
</cache>
</ehcache>
4、Springboot配置文件application.properties中引入ehcache.xml配置文件,如图所示
5、编写EhcacheUtil.java工具类,该工具类中一般均为静态方法,方便调用。另外,自己可根据需求自行修改,工具类方法大家可以根据需求调用。
package com.wonddream.utils;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.wonddream.beans.ServiceSwitchDTO;
import com.wonddream.consts.EhCacheConfigConsts;
import com.wonddream.iservice.ServiceSwitchIservice;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;
public class EhCacheUtil {
private static final Logger logger = LoggerFactory.getLogger(EhCacheUtil.class);
private static CacheManager cacheManager = null;
private static Cache cache = null;
static{
// initCacheManager("/wonddream/src/main/resources/config/ehcache.xml");
initCacheManager();
initCache("wonddream_ehcache");
}
/**
*
* 初始化缓存管理容器
*/
public static CacheManager initCacheManager() {
try {
if (cacheManager == null)
cacheManager = CacheManager.getInstance();
} catch (Exception e) {
logger.error("******初始化CacheManager异常",e);
}
return cacheManager;
}
/**
*
* 初始化缓存管理容器
*
* @param path ehcache.xml存放的路徑
*/
public static CacheManager initCacheManager(String path) {
try {
if (cacheManager == null) {
cacheManager = CacheManager.getInstance().create(path);
}
} catch (Exception e) {
logger.error("******初始化CacheManager异常",e);
}
return cacheManager;
}
/**
* 初始化cache
*/
public static Cache initCache(String cacheName) {
checkCacheManager();
if (null == cacheManager.getCache(cacheName)) {
cacheManager.addCache(cacheName);
}
cache = cacheManager.getCache(cacheName);
return cache;
}
/**
* 添加缓存
* @param key 关键字
* @param value 值
*/
public static void put(Object key, Object value) {
checkCache();
// 创建Element,然后放入Cache对象中
Element element = new Element(key, value);
cache.put(element);
}
/**
* 获取cache
* @param key 关键字
* @return
*/
public static Object get(Object key) {
checkCache();
Element element = cache.get(key);
if (null == element) {
return null;
}
return element.getObjectValue();
}
/**
* 初始化缓存
* @param cacheName 缓存名称
* @param maxElementsInMemory 元素最大数量
* @param overflowToDisk 是否持久化到硬盘
* @param eternal 是否会死亡
* @param timeToLiveSeconds 缓存存活时间
* @param timeToIdleSeconds 缓存的间隔时间
* @return 缓存
* @throws Exception
*/
public static Cache initCache(String cacheName, int maxElementsInMemory, boolean overflowToDisk, boolean eternal,
long timeToLiveSeconds, long timeToIdleSeconds) throws Exception {
try {
CacheManager singletonManager = CacheManager.create();
Cache myCache = singletonManager.getCache(cacheName);
if (myCache != null) {
CacheConfiguration config = cache.getCacheConfiguration();
config.setTimeToLiveSeconds(timeToLiveSeconds);
config.setMaxEntriesLocalHeap(maxElementsInMemory);
config.setOverflowToDisk(overflowToDisk);
config.setEternal(eternal);
config.setTimeToIdleSeconds(timeToIdleSeconds);
}
if (myCache == null) {
Cache memoryOnlyCache = new Cache(cacheName, maxElementsInMemory, overflowToDisk, eternal, timeToLiveSeconds,
timeToIdleSeconds);
singletonManager.addCache(memoryOnlyCache);
myCache = singletonManager.getCache(cacheName);
}
return myCache;
} catch (Exception e) {
throw new Exception("init cache " + cacheName + " failed!!!");
}
}
/**
* 初始化cache
* @param cacheName cache的名字
* @param timeToLiveSeconds 有效时间
* @return cache 缓存
* @throws Exception
*/
public static Cache initCache(String cacheName, long timeToLiveSeconds) throws Exception {
return EhCacheUtil.initCache(cacheName, EhCacheConfigConsts.MAXELEMENTSINMEMORY, EhCacheConfigConsts.OVERFLOWTODISK,
EhCacheConfigConsts.ETERNAL, timeToLiveSeconds, EhCacheConfigConsts.TIMETOIDLESECONDS);
}
/**
* 初始化Cache
* @param cacheName cache容器名
* @return cache容器
* @throws Exception
*/
public static Cache initMyCache(String cacheName) throws Exception {
return EhCacheUtil.initCache(cacheName, EhCacheConfigConsts.TIMETOlIVESECONDS);
}
/**
* 修改缓存容器配置
* @param cacheName 缓存名
* @param timeToLiveSeconds 有效时间
* @param maxElementsInMemory 最大数量
* @throws Exception
*/
public static boolean modifyCache(String cacheName, long timeToLiveSeconds, int maxElementsInMemory) throws Exception {
try {
if (StringUtil.isNotBlank(cacheName) && timeToLiveSeconds != 0L && maxElementsInMemory != 0) {
CacheManager myManager = CacheManager.create();
Cache myCache = myManager.getCache(cacheName);
CacheConfiguration config = myCache.getCacheConfiguration();
config.setTimeToLiveSeconds(timeToLiveSeconds);
config.setMaxEntriesLocalHeap(maxElementsInMemory);
return true;
} else {
return false;
}
} catch (Exception e) {
throw new Exception("modify cache " + cacheName + " failed!!!");
}
}
/**
* 向指定容器中设置值
* @param vesselName 容器名
* @param key 键
* @param value 值
* @return 返回真
* @throws Exception 异常
*/
public static boolean setValue(String cacheName, String key, Object value) throws Exception {
try {
CacheManager myManager = CacheManager.create();
Cache myCache = myManager.getCache(cacheName);
if (myCache == null) {
myCache = initCache(cacheName);
}
myCache.put(new Element(key, value));
return true;
} catch (Exception e) {
throw new Exception("set cache " + cacheName + " failed!!!");
}
}
/**
* 向指定容器中设置值
* @param cacheName 容器名
* @param key 键
* @param value 值
* @param timeToIdleSeconds 间歇时间
* @param timeToLiveSeconds 存活时间
* @return 真
* @throws Exception 抛出异常
*/
public static boolean setValue(String cacheName, String key, Object value, Integer timeToLiveSeconds) throws Exception {
try {
CacheManager myManager = CacheManager.create();
Cache myCache = myManager.getCache(cacheName);
if (myCache == null) {
initCache(cacheName, timeToLiveSeconds);
myCache = myManager.getCache(cacheName);
}
myCache.put(new Element(key, value, EhCacheConfigConsts.ETERNAL, EhCacheConfigConsts.TIMETOIDLESECONDS, timeToLiveSeconds));
return true;
} catch (Exception e) {
throw new Exception("set cache " + cacheName + " failed!!!");
}
}
/**
* 从ehcache的指定容器中取值
* @createTime 2012-4-23
* @param key 键
* @return 返回Object类型的值
* @throws Exception 异常
*/
public static Object getValue(String cacheName, String key) throws Exception {
try {
CacheManager myManager = CacheManager.create();
Cache myCache = myManager.getCache(cacheName);
if (myCache == null) {
myCache = initMyCache(cacheName);
}
return myCache.get(key).getObjectValue();
} catch (Exception e) {
return null;
}
}
/**
* 删除指定的ehcache容器
* @param vesselName
* @return 真
* @throws Exception 失败抛出异常
*/
public static boolean removeEhcache(String cacheName) throws Exception {
try {
CacheManager myManager = CacheManager.create();
myManager.removeCache(cacheName);
return true;
} catch (Exception e) {
throw new Exception("remove cache " + cacheName + " failed!!!");
}
}
/**
* 删除所有的EHCache容器
* @param cacheName 容器名
* @return 返回真
* @throws Exception 失败抛出异常
*/
public static boolean removeAllEhcache(String cacheName) throws Exception {
try {
CacheManager myManager = CacheManager.create();
myManager.removeAllCaches();
return true;
} catch (Exception e) {
throw new Exception("remove cache " + cacheName + " failed!!!");
}
}
/**
* 删除EHCache容器中的元素
* @param cacheName 容器名
* @param key 键
* @return 真
* @throws Exception 失败抛出异常
*/
public static boolean removeElment(String cacheName, String key) throws Exception {
try {
CacheManager myManager = CacheManager.create();
Cache myCache = myManager.getCache(cacheName);
myCache.remove(key);
return true;
} catch (Exception e) {
throw new Exception("remove cache " + cacheName + " failed!!!");
}
}
/**
* 删除指定容器中的所有元素
* @param cacheName 容器名
* @param key 键
* @return 真
* @throws Exception 失败抛出异常
*/
public static boolean removeAllElment(String cacheName, String key) throws Exception {
try {
CacheManager myManager = CacheManager.create();
Cache myCache = myManager.getCache(cacheName);
myCache.removeAll();
return true;
} catch (Exception e) {
throw new Exception("remove cache " + cacheName + " failed!!!");
}
}
/**
* 释放CacheManage
*/
public static void shutdown() {
cacheManager.shutdown();
}
/**
* 移除cache
* @param cacheName
*/
public static void removeCache(String cacheName) {
checkCacheManager();
cache = cacheManager.getCache(cacheName);
if (null != cache) {
cacheManager.removeCache(cacheName);
}
}
/**
* 移除cache中的key
* @param cacheName
*/
public static void remove(String key) {
checkCache();
cache.remove(key);
}
/**
* 移除所有cache
*/
public static void removeAllCache() {
checkCacheManager();
cacheManager.removeAllCaches();
}
/**
*
* 移除所有Element
*/
public static void removeAllKey() {
checkCache();
cache.removeAll();
}
/**
* 获取所有的cache名称
* @return
*/
public static String[] getAllCaches() {
checkCacheManager();
return cacheManager.getCacheNames();
}
/**
* 获取Cache所有的Keys
* @return
*/
public static List getKeys() {
checkCache();
return cache.getKeys();
}
/**
* 检测cacheManager
*/
private static void checkCacheManager() {
if (null == cacheManager) {
throw new IllegalArgumentException("调用前请先初始化CacheManager值:EhCacheUtil.initCacheManager");
}
}
private static void checkCache() {
if (null == cache) {
throw new IllegalArgumentException("调用前请先初始化Cache值:EhCacheUtil.initCache(参数)");
}
}
}
6、实现Springboot项目启动热加载缓存数据的关键步骤:编写CacheServiceUtil工具类,实现CommandLineRunner接口。该类添加@Component注解,交予Spring进行管理。
CommandLineRunner是Spring Boot提供的一个接口,实现改接口的类可以再Springboot项目启动后自执行,从而实现一些项目数据的初始化或者热加载。CommandLineRunner详细使用参见:XXXXXXXXXXXXXX(文章整理中)
package com.wonddream.cache;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.wonddream.beans.ServiceSwitchDTO;
import com.wonddream.iservice.ServiceSwitchIservice;
import com.wonddream.utils.EhCacheUtil;
import com.wonddream.utils.StringUtil;
@Component
//如果存在多个实现CommandLineRunner的接口,会按照设置的顺序执行
@Order(value=1)
public class CacheServiceUtil implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(CacheServiceUtil.class);
@Autowired
private ServiceSwitchIservice serviceSwitchIservice;
@Override
public void run(String... args) throws Exception {
logger.info("******启动热加载缓存数据");
//查询数据库的方法,关于springboot整合mybatis的方法参见博客:https://blog.csdn.net/weixin_42315600/article/details/84139404
List<ServiceSwitchDTO> list= serviceSwitchIservice.selectAll();
logger.info("******热加载数据查询结果:"+list.toArray());
for(ServiceSwitchDTO serviceSwitchDTO:list) {
String switchKey = serviceSwitchDTO.getSwitchKey();
logger.info("switchKey="+switchKey);
String switchValue = serviceSwitchDTO.getSwitchValue();
logger.info("switchValue="+switchValue);
EhCacheUtil.put(switchKey, switchValue);
}
}
/**
* 获取cache
* @param key 关键字
* @return
*/
public String getJVM(Object key) {
String value = (String)EhCacheUtil.get(key);
if (StringUtil.isBlank(value)) {
logger.info("查询缓存失败,开始从数据查询数据");
//查询数据库,并放入缓存,此处selectBySwitchKey方法,实现了ehcache,查询接口之后会自动放入ehcache
//这里是ehcache
value = serviceSwitchIservice.selectBySwitchKey(String.valueOf(key));
if(StringUtil.isBlank(value)) {
return null;
}
return value;
}
return value;
}
/**
* 移除cache
* @param cacheName
*/
public void delJVM(String key) {
EhCacheUtil.remove(key);
}
}
7、Springboot启动类,添加@enableCaching注解,项目启动时开启缓存。
8、启动Springboot项目,查看日志情况:
9、Ehcache的注解用法,如下图。在本文的CacheServiceUtil类中的getJVM(Object key) 方法中有使用到该功能。
关于Ehcache注解的使用,详见:XXXXXXXXXXXXXXX(文章整理中)