<?xml version="1.0" encoding="UTF-8" ?> <!--Ehcache3.xx配置 --> <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-3.0.xsd"> <!--磁盘储存路径--> <persistence directory="D:/ehcacheData"/> <!--用于缓存菜单权限的管理--> <cache alias="sysPermissionCache"> <key-type>java.lang.String</key-type> <value-type>org.jd.data.netty.big.window.chat.entity.PermissionVo</value-type> <!--<value-type>java.lang.Object</value-type>--> <!-- 省略 <expiry> 标签 就不过期了 --> <expiry> <!--缓存的生存时间(TTL)为28800秒--> <ttl unit="seconds">28800</ttl> <!--缓存的空闲时间(TTI)为20秒 无法同时配置条目的生存时间(TTL)和空闲时间(TTI)--> <!--<tti unit="seconds"> 20</tti>--> </expiry> <resources> <!--堆外内存的大小限制为1024MB。--> <offheap unit="MB">200</offheap> </resources> </cache> <!--第二种配置方式 --> <!-- <cache alias="sysUserCache" uses-template="sysUserCache_template"/> <cache-template name="sysUserCache_template"> <key-type>java.lang.String</key-type> <value-type>org.jd.auth.data.security.server.domain.SysUser</value-type> <expiry> <ttl unit="hours">30</ttl> </expiry> <heap unit="entries">2</heap> <!–堆内存的大小限制为2个条目–> <jsr107:mbeans enable-statistics="true" enable-management="true"/> </cache-template>--> <!--用于sysUserCache的管理--> <!--<cache alias="sysUserCache"> <key-type>java.lang.String</key-type> <value-type>org.jd.auth.data.security.server.domain.SysUser</value-type> <!– 省略 <expiry> 标签 就不过期了 –> <expiry> <!–缓存的生存时间(TTL)为30秒–> <ttl unit="seconds">30</ttl> <!–缓存的空闲时间(TTI)为20秒 无法同时配置条目的生存时间(TTL)和空闲时间(TTI)–> <!–<tti unit="seconds"> 20</tti>–> </expiry> <resources> <!–堆内存的大小限制为2个条目–> <heap unit="entries">2</heap> <!–堆外内存的大小限制为10MB。–> <offheap unit="MB">10</offheap> <!–磁盘缓存 persistent属性用于指定磁盘缓存是否持久化–> <disk unit="MB" persistent="false">20</disk> </resources> </cache>--> <!--用于sysUserCache的管理--> <!--<cache alias="sysGroupCache"> <key-type>java.lang.String</key-type> <value-type>org.jd.data.netty.big.window.chat.entity.SSOUser</value-type> <!– 省略 <expiry> 标签 就不过期了 –> <expiry> <!–缓存的生存时间(TTL)为30秒–> <ttl unit="seconds">30</ttl> <!–缓存的空闲时间(TTI)为20秒 无法同时配置条目的生存时间(TTL)和空闲时间(TTI)–> <!– <tti unit="seconds"> 20</tti>–> </expiry> <resources> <!–堆内存的大小限制为2个条目–> <heap unit="entries">2</heap> <!–堆外内存的大小限制为10MB。–> <offheap unit="MB">10</offheap> <!–磁盘缓存 persistent属性用于指定磁盘缓存是否持久化–> <disk unit="MB" persistent="false">20</disk> </resources> </cache>--> </config> <!-- 当内存中不够存储时,存储到指定数据在磁盘中的存储位置。 --> <!--<diskStore path="data/ehcache"/>--> <!-- 必须的属性: maxElementsInmemory—— 在内存中缓存的element的最大数目 maxElementsOnDisk——在磁盘上缓存的elements的最大数目,0表示不限制 eternal——设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断 overFlowToDisk——设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上--> <!-- 可选的属性: timeToIdleSeconds——可闲置时间。当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大 timeToLiveSeconds——缓存element的有效生命期,默认是0。也就是element存活时间无穷大 diskSpoolBufferSizeMB——设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区. diskPersistent——在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 diskExpiryThreadIntervalSeconds——磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作 memoryStoreEvictionPolicy——当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) clearOnFlush——内存达到最大时是否清除--> <!-- 默认缓存配置 --> <!-- <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="0" timeToLiveSeconds="600" overflowToDisk="false" diskPersistent="false" memoryStoreEvictionPolicy="LRU"/>--> <!-- 自定义,service缓存配置 eternal: 缓存是否永远不销毁 maxElementsInMemory: 缓存可以存储的总记录量 overflowToDisk: 当缓存中的数据达到最大值时,是否把缓存数据写入磁盘 diskPersistent: 是否启用强制命令将缓存出入磁盘 timeToIdleSeconds: 当缓存闲置时间超过该值,则缓存自动销毁,如果该值是0就意味着元素可以停顿无穷长的时间 timeToLiveSeconds: 缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值, 这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间 memoryStoreEvictionPolicy: 缓存满了之后的淘汰算法 --> <!--timeToLiveSeconds 当缓存存活n秒后销毁 --> <!-- 缓存配置 name:缓存名称。 maxElementsInMemory:缓存最大个数。 eternal:对象是否永久有效,一但设置了,timeout将不起作用。 timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。 timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。 overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 maxElementsOnDisk:硬盘最大缓存个数。 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"/> <!– 默认缓存 –> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </defaultCache> <!– 测试 –> <cache name="GoodsType" eternal="false" timeToIdleSeconds="2400" timeToLiveSeconds="2400" maxEntriesLocalHeap="10000" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" overflowToDisk="false" memoryStoreEvictionPolicy="LRU"> </cache> <!–测试 –> <cache name="serviceCache" eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0" timeToLiveSeconds="3600" memoryStoreEvictionPolicy="LRU"/> --> <!--ehcache.xml配置文件详解 diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。 defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。 name:缓存名称。 maxElementsInMemory:缓存最大数目 maxElementsOnDisk:硬盘最大缓存个数。 eternal:对象是否永久有效,一但设置了,timeout将不起作用。 overflowToDisk:是否保存到磁盘,当系统宕机时 timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。 timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。 diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 clearOnFlush:内存数量最大时是否清除。 FIFO,first in first out,先进先出。 LFU, Less Frequently Used,一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。 LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有--> <!-- </ehcache>-->
封装工具类
package org.jd.data.netty.big.window.chat.util; import cn.hutool.core.date.StopWatch; import lombok.extern.slf4j.Slf4j; import org.ehcache.Cache; import org.ehcache.CacheManager; import org.ehcache.config.CacheConfiguration; import org.ehcache.config.Configuration; import org.ehcache.config.builders.CacheConfigurationBuilder; import org.ehcache.config.builders.CacheManagerBuilder; import org.ehcache.config.builders.ExpiryPolicyBuilder; import org.ehcache.config.builders.ResourcePoolsBuilder; import org.ehcache.config.units.MemoryUnit; import org.ehcache.expiry.ExpiryPolicy; import org.ehcache.impl.serialization.PlainJavaSerializer; import org.ehcache.xml.XmlConfiguration; import javax.cache.CacheException; import java.io.File; import java.io.Serializable; import java.net.URL; import java.time.Duration; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** * 单例内部类实现工具类 */ @Slf4j public class SSOEhcacheTool { private SSOEhcacheTool() { System.out.println("是不是每次调用都会创建EhcacheUtils这个对象"); } private static class EhcacheUtilHandler { private static SSOEhcacheTool newInstance = new SSOEhcacheTool(); } public static SSOEhcacheTool getInstance() { return SSOEhcacheTool.EhcacheUtilHandler.newInstance; } /** * 保证整个系统中CacheManager只有一个 */ private static CacheManager cacheManager; // 缓存别名 private static final String CACHE_NAME_USER = "cache-user"; private static final String CACHE_NAME_SYS = "cache-sys"; // 静态代码块在类加载初始化阶段被执行 static { cacheManagerInit(); } private static CacheManager cacheManagerInit() { System.out.println("方法会被执行多次吗?cacheManagerInit" + System.currentTimeMillis()); /** * 加载classpath路径下面的配置文件 创建CacheManager */ StopWatch stopWatch = new StopWatch("统计缓存ehcache初始化任务"); try { stopWatch.start("EhcacheUtils-load-ehcache-init"); URL configUrl = SSOEhcacheTool.class.getResource("/cache/ehcache.xml"); Configuration xmlConfig = new XmlConfiguration(configUrl); cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig); cacheManager.init(); // 只有执行这个方法,才能获得cacheManager实例 stopWatch.stop(); } catch (CacheException e) { System.err.println("ehcache load ehcache configure error: " + e.getMessage()); e.printStackTrace(); } String taskName = stopWatch.getLastTaskName(); double totalTime = stopWatch.getTotalTimeSeconds(); System.out.println("任务 " + taskName + " 耗时: " + totalTime + " 秒"); // 打印出耗时 String result = stopWatch.prettyPrint(); System.err.println("打印出耗时: " + result); return cacheManager; } private volatile Class<?> initValue; /** * 初始化缓存实体 * @param cacheClass */ public void initCacheEntity(Class<?> cacheClass){ this.initValue = cacheClass; } /** * 用于测试下,系统的cacheManager是否时唯一对象 * * @return {@link CacheManager} */ private static CacheManager getCacheManager() { return cacheManager; } /** * 存在则返回,不存在,则创建一个 * @param cacheAliasName * @return */ public Cache<String, Object> getCache(String cacheAliasName) { Cache cache = getCacheManager().getCache(cacheAliasName, String.class, initValue); if(Objects.isNull(cache)){ throw new RuntimeException("请检查ehcache.xml配置,缓存名称 {"+cacheAliasName+"} 不存在!"); } return cache; } /** * 存在则返回,不存在,则创建一个 * 不使用配置文件创建CacheManager管理器实例 * @param cacheClass * @return */ public Cache<String, Object> getCache(Class cacheClass) { Cache theCache = ehcacheManager().getCache(cacheClass.getName(), String.class, Object.class); if (Objects.isNull(theCache)) { theCache = newCache(cacheClass); } return theCache; } public Cache newCache(Class cacheClass) { System.out.println("缓存不存在时自动创建: "+cacheClass.getName()); String mapKey = cacheClass.getClass()+"_"+cacheClass.getName(); mapKey = mapKey.intern(); // 该方法,如果变量存在,就直接使用,如果不存在,则加入到常量池 if (Objects.isNull(cacheRunMapKeys.get(mapKey))) { synchronized (mapKey) { if (Objects.isNull(cacheRunMapKeys.get(mapKey))) { Cache newCache = getCacheManager().createCache( cacheClass.getName(), // 别名 CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Object.class, ResourcePoolsBuilder.heap(10)) .withExpiry(ExpiryPolicy.NO_EXPIRY) .build() ); cacheRunMapKeys.put(mapKey, ""); return newCache; } } } return getCache(cacheClass); } /** * 配置文件不支持Object.Class配置 * 使用的是配置文件初始化提供的CacheManager * 配置文件中没有,则创建一个新的缓存 * @param aliasCacheName * @return */ /* public Cache newCache(String aliasCacheName) { String mapKey = aliasCacheName; mapKey = mapKey.intern(); // 该方法,如果变量存在,就直接使用,如果不存在,则加入到常量池 if (Objects.isNull(cacheRunMapKeys.get(mapKey))) { synchronized (mapKey) { if (Objects.isNull(cacheRunMapKeys.get(mapKey))) { Cache newCache = getCacheManager().createCache( aliasCacheName, // 别名 CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Object.class, ResourcePoolsBuilder.heap(10)) .withExpiry(ExpiryPolicy.NO_EXPIRY) .build() ); cacheRunMapKeys.put(mapKey, ""); return newCache; } } } return getCache(aliasCacheName); }*/ private Map<String, String> cacheRunMapKeys = new ConcurrentHashMap<>(); /** * 研究下这些参数的大小 */ private static final String cache_disk_path = ""; private static final Long cache_heap_size = 0l; private static final String cache_heap_unit = ""; private static final Long cache_offheap_size = 0L; private static final Long cache_disk_size = 20L; private static final String cache_offheap_unit = ""; private static final String cache_disk_unit = ""; /** * 不使用配置文件初始化: CacheManager * * @return {@link CacheManager} */ public CacheManager createCacheManager() { CacheManager cacheManager = CacheManagerBuilder .persistence(cache_disk_path) //硬盘缓存文件位置 .builder(CacheManagerBuilder .newCacheManagerBuilder() .withDefaultSizeOfMaxObjectGraph(20000) //cacheManager级别设置默认最大对象图大小 .withCache("LocalCacheMax", CacheConfigurationBuilder //缓存名称与缓存设置 "LocalCacheMax" 为缓存别名 .newCacheConfigurationBuilder(String.class, Serializable.class, ResourcePoolsBuilder .newResourcePoolsBuilder() .heap(cache_heap_size, MemoryUnit.valueOf(cache_heap_unit)) .offheap(cache_offheap_size, MemoryUnit.valueOf(cache_offheap_unit)) .disk(cache_disk_size, MemoryUnit.valueOf(cache_disk_unit), true)) .withExpiry(ExpiryPolicy.NO_EXPIRY) //设置永不过期 .withDiskStoreThreadPool("persistenceThread", 5) )) .build(true); return (CacheManager) cacheManager.getCache("LocalCacheMax", String.class, Serializable.class); } public CacheManager ehcacheManager() { //配置占用资源 //heap 设置占用虚拟机内存大小 //offheap 设置占用虚拟机外内存大小 //disk 设置占用磁盘空间大小,需结合下方ehcacheManager设置存储位置,否则会报错 ResourcePoolsBuilder resourcePoolsBuilder = ResourcePoolsBuilder.newResourcePoolsBuilder() .heap(20, MemoryUnit.MB) .offheap(30, MemoryUnit.MB) .disk(100, MemoryUnit.MB); //配置存储键值格式及过期策略 //如:withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofHours(24)) 最后一次使用后计算,所存储的时间超过24小时 //如:withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofHours(24))) 从缓存开始计算,所存储的时间超过24小时 //如:withExpiry(ExpiryPolicyBuilder.noExpiration()) 永不过期 CacheConfiguration<String, Object> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Object.class, resourcePoolsBuilder) .withValueSerializer(new PlainJavaSerializer<>(this.getClass().getClassLoader())) .withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofHours(24))) .build(); //获取最终打包jar所在位置 这是Spring-boot专有 /*String path = new ApplicationHome(getClass()).getSource().getParentFile().toString(); System.out.println(path);*/ //以下各行配置分别对应 //配置硬盘缓存存储地址 //最大对象默认大小 //缓存记录最大条数 String path = "D:/home/data"; // 硬盘缓存的逻辑"D:/home/data/ehcache" CacheManager ehcacheManager = CacheManagerBuilder.newCacheManagerBuilder() .with(CacheManagerBuilder.persistence(new File(path, "ehcache"))) .withDefaultSizeOfMaxObjectSize(500, MemoryUnit.KB) .withDefaultSizeOfMaxObjectGraph(2000) .withCache(CACHE_NAME_USER, cacheConfiguration) .withCache(CACHE_NAME_SYS, cacheConfiguration) .build(true); return ehcacheManager; } /** * 根据cacheKey获取对应的值 * * @param cacheName 配置文件中配置缓存的名称 * @param cacheKey 缓存Key * @return {@link Object} */ public Object get(String cacheName, String cacheKey) { Cache cache = getCache(cacheName); return cache.get(cacheKey); } /** * @param cacheName 配置文件中配置缓存的名称 * @param cacheKey 缓存key * @param value 缓存值 */ public void put(String cacheName, String cacheKey, Object value) { Cache cache = getCache(cacheName); cache.put(cacheKey, value); } /** * @param cacheName 配置文件中配置缓存的名称 * @param value 缓存值 */ public void putAll(String cacheName, Map<String, Object> value) { Cache cache = getCache(cacheName); cache.putAll(value); } /** * 判断缓存key是否存在 * * @param cacheName 配置文件中配置缓存的名称 * @param key 缓存key * @return {@link Boolean} */ public boolean exist(String cacheName, String key) { Cache cache = getCache(cacheName); return cache.containsKey(key); } /** * 删除指定key的缓存 * * @param cacheName 配置文件中配置缓存的名称 * @param key 缓存key */ public void evict(String cacheName, String key) { Cache cache = getCache(cacheName); cache.remove(key); } }
测试代码
package org.jd.data.netty.big.window.chat; import cn.hutool.json.JSONUtil; import org.ehcache.Cache; import org.ehcache.CacheManager; import org.jd.data.netty.big.window.chat.entity.PermissionVo; import org.jd.data.netty.big.window.chat.entity.SSOUser; import org.jd.data.netty.big.window.chat.util.SSOEhcacheTool; import java.util.*; /** */ public class ChatMessageUIProvider { public static void main(String[] args) { /*Object result= HttpUtil.get("http://localhost:8810/account/orderPay/findList"); System.out.println("返回值是啥: "+result);*/ SSOEhcacheTool ssoEhcacheTool = SSOEhcacheTool.getInstance(); // String cacheAliasName= "sysPermissionCache"; Cache<String, Object> resultCache = ssoEhcacheTool.getCache(PermissionVo.class); Map<String, PermissionVo> initData = new HashMap<>(); List<PermissionVo> temList = new ArrayList<>(); PermissionVo permissionVo = new PermissionVo(); permissionVo.setIcon("www.baidu.com"); permissionVo.setName("缓存测试"); permissionVo.setId(String.valueOf(1)); permissionVo.setParentId(String.valueOf(0)); temList.add(permissionVo); PermissionVo permissionVo2 = new PermissionVo(); permissionVo2.setIcon("www.baidu.com2"); permissionVo2.setName("缓存测试2"); permissionVo2.setId(String.valueOf(2)); permissionVo2.setParentId(String.valueOf(2)); initData.put("1_1", permissionVo); initData.put("2_1", permissionVo2); temList.add(permissionVo2); resultCache.putAll(initData); Set<String> setKeys = new HashSet<>(); setKeys.add("1_1"); setKeys.add("2_1"); System.out.println("获取缓存中map: " + resultCache.getAll(setKeys)+" ; 缓存的别名为: "); resultCache.put("sysPermissionCache_field_", permissionVo); System.out.println("冲缓存中取出的对象:" + resultCache.get("sysPermissionCache_field_")); resultCache.remove("sysPermissionCache_field_"); System.out.println("移除缓存后,再次获取缓存: " + resultCache.get("sysPermissionCache_field_")); /*System.out.println("====================temList================="); resultCache.put("temList",temList); System.out.println("获取缓存的集合: "+resultCache.get("temList")); SSOUser ssoUser = new SSOUser(); ssoUser.setUserId("userid"); ssoUser.setUserName("战三"); Cache<String, Object> ssoEhcacheToolCache = ssoEhcacheTool.getCache(SSOUser.class); ssoEhcacheToolCache.put("2",temList); System.out.println("获取缓存的集合SSOUser: "+ssoEhcacheToolCache.get("2")); System.out.println("====================下面创建配置文件中不存在缓存================="); System.out.println("存储别名为: " + SSOUser.class.getName()); System.out.println("未在配置文件配置缓存,是否会自动创建: " + JSONUtil.toJsonStr(ssoEhcacheToolCache.get("1")));*/ } }