Springboot集成Ehcache,并结合CommandLineRunner接口实现Springboot项目启动时热加载数据库数据至缓存

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接口。该类添加@common注解,交予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(文章整理中)

猜你喜欢

转载自blog.csdn.net/weixin_42315600/article/details/84942294