【Ehcache】ehcache2.5.2缓存的使用
缓存的名字是ehcache。。。老是记得是encache....
官方PDF文档:http://www.ehcache.org/documentation/ehcache-2.5.x-documentation.pdf
0.需要的jar包:
1.首先要了解缓存清除策略,官方文档给出的有
超过缓存指定的数量的时候按指定策略清除缓存的数据。参考:MemoryStoreEvictionPolicy类:
LRU - least recently used(最近最少使用) LFU - least frequently used(最不经常使用) FIFO - first in first out, the oldest element by creation time(清除最早缓存的数据,不关心是否经常使用)
CLOCK---FIFO - first in first out, the oldest element by creation time.(与FIFO一样)
2.一个简单的使用
1.使用缓存
配置文件:
<ehcache updateCheck="false" dynamicConfig="false"> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="1000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="cache_test" maxElementsInMemory="2" eternal="false" timeToIdleSeconds="60" timeToLiveSeconds="60" maxElementsOnDisk="2" overflowToDisk="true" diskPersistent="false" memoryStoreEvictionPolicy="FIFO" /> </ehcache>
各配置参数的含义:
maxElementsInMemory:缓存中允许创建的最大对象数
maxElementsOnDisk:磁盘中允许的最多对象数
eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。
timeToIdleSeconds:缓存数据的钝化时间,也就是在一个元素消亡之前,两次访问时间的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0 就意味着元素可以停顿无穷长的时间。
timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。
overflowToDisk:内存不足时,是否启用磁盘缓存。
diskPersistent 是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache名称,后缀名为data的文件。指重启jvm后,数据是否有效。默认为false。
memoryStoreEvictionPolicy:缓存满了之后的淘汰算法。
如果应用需要配置多个不同命名并采用不同参数的Cache,可以相应修改配置文件,增加需要的Cache配置即可。
两个时间的详细解释:
timeToLiveSeconds -->当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清除;即缓存自创建日期起能够存活的最长时间,单位为秒(s)
timeToIdleSeconds --> 当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清空;即缓存被创建后,最后一次访问时间到缓存失效之时,两者之间的间隔,单位为秒(s)
timeToLiveSeconds必须大于timeToIdleSeconds才有意义。
测试代码:
package encache; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; public class FirstCache { private static final Logger log = LoggerFactory.getLogger(FirstCache.class.getName()); // 1.创建CacheManager // CacheManager cacheManager = CacheManager.create("E:/MavenEclipseWorkspace/encache/target/classes/ehcache.xml");// 也可以通过URL制定 //一般用下面这种方式创建Cachemanager // CacheManager cacheManager = CacheManager.create();//默认读取classpath目录下面的ehcache.xml CacheManager cacheManager = new CacheManager();//默认读取classpath目录下面的ehcache.xml public FirstCache() { // 2.创建Cache Cache cache = cacheManager.getCache("cache_test"); // 3.存取元素 cache.put(new Element("firstCache", "第一个缓存元素")); // 4.获取元素 Element element = cache.get("firstCache"); log.info("获取的缓存元素是:{}", element); long creationTime = element.getCreationTime(); long expirationTime = element.getExpirationTime(); log.info("creationTime: {}", new Date(creationTime)); log.info("expirationTime: {}", new Date(expirationTime)); int diskStoreSize = cache.getDiskStoreSize(); int cacheSize = cache.getKeys().size(); log.info("diskStoreSize:{}", diskStoreSize); log.info("cacheSize: {}", cacheSize); } public static void main(String[] args) throws Exception { new FirstCache(); } }
结果:(注意存活时间是60s,注意标红的信息)
2018-09-09 14:45:57 [net.sf.ehcache.CacheManager]-[DEBUG] Configuring ehcache from classpath. 2018-09-09 14:45:57 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from ehcache.xml found in the classpath: file:/E:/MavenEclipseWorkspace/encache/target/classes/ehcache.xml 2018-09-09 14:45:57 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from URL: file:/E:/MavenEclipseWorkspace/encache/target/classes/ehcache.xml 2018-09-09 14:45:57 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from InputStream 2018-09-09 14:45:58 [net.sf.ehcache.config.DiskStoreConfiguration]-[DEBUG] Disk Store Path: C:\Users\liqiang\AppData\Local\Temp\ 2018-09-09 14:45:58 [net.sf.ehcache.util.PropertyUtil]-[DEBUG] propertiesString is null. 2018-09-09 14:45:58 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheManagerEventListenerFactory class specified. Skipping... 2018-09-09 14:45:59 [net.sf.ehcache.Cache]-[DEBUG] No BootstrapCacheLoaderFactory class specified. Skipping... 2018-09-09 14:45:59 [net.sf.ehcache.Cache]-[DEBUG] CacheWriter factory not configured. Skipping... 2018-09-09 14:45:59 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheExceptionHandlerFactory class specified. Skipping... 2018-09-09 14:45:59 [net.sf.ehcache.Cache]-[DEBUG] No BootstrapCacheLoaderFactory class specified. Skipping... 2018-09-09 14:45:59 [net.sf.ehcache.Cache]-[DEBUG] CacheWriter factory not configured. Skipping... 2018-09-09 14:45:59 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheExceptionHandlerFactory class specified. Skipping... 2018-09-09 14:45:59 [net.sf.ehcache.store.MemoryStore]-[DEBUG] Initialized net.sf.ehcache.store.MemoryStore for cache_test 2018-09-09 14:45:59 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file cache_test.data 2018-09-09 14:45:59 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file cache_test.index 2018-09-09 14:45:59 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Matching data file missing (or empty) for index file. Deleting index file C:\Users\liqiang\AppData\Local\Temp\cache_test.index 2018-09-09 14:45:59 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file cache_test.index 2018-09-09 14:45:59 [net.sf.ehcache.Cache]-[DEBUG] Initialised cache: cache_test 2018-09-09 14:45:59 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] CacheDecoratorFactory not configured. Skipping for 'cache_test'. 2018-09-09 14:45:59 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] CacheDecoratorFactory not configured for defaultCache. Skipping for 'cache_test'. 2018-09-09 14:45:59 [net.sf.ehcache.store.disk.Segment]-[DEBUG] put added 0 on heap 2018-09-09 14:45:59 [encache.FirstCache]-[INFO] 获取的缓存元素是:[ key = firstCache, value=第一个缓存元素, version=1, hitCount=1, CreationTime = 1536475559759, LastAccessTime = 1536475559799 ] 2018-09-09 14:45:59 [encache.FirstCache]-[INFO] creationTime: Sun Sep 09 14:45:59 CST 2018 2018-09-09 14:45:59 [encache.FirstCache]-[INFO] expirationTime: Sun Sep 09 14:46:59 CST 2018 2018-09-09 14:45:59 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault removed 0 from heap 2018-09-09 14:45:59 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault added 0 on disk 2018-09-09 14:45:59 [encache.FirstCache]-[INFO] diskStoreSize:0 2018-09-09 14:45:59 [encache.FirstCache]-[INFO] cacheSize: 1
并且在:C:\Users\liqiang\AppData\Local\Temp文件夹下面生成一个cache_test.data的文件。
删除缓存只需要采用如下方法:
// 4.删除一个元素 cache.remove("key");
2.获取缓存配置
package encache; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import net.sf.ehcache.config.CacheConfiguration; import net.sf.ehcache.store.MemoryStoreEvictionPolicy; public class FirstCache { private static final Logger log = LoggerFactory.getLogger(FirstCache.class.getName()); // 1.创建CacheManager CacheManager cacheManager = new CacheManager();// 默认读取classpath目录下面的ehcache.xml public FirstCache() { // 2.创建Cache Cache cache = cacheManager.getCache("cache_test"); CacheConfiguration cacheConfiguration = cache.getCacheConfiguration(); // 2.1获取满了之后的清除策略 MemoryStoreEvictionPolicy policy = cacheConfiguration.getMemoryStoreEvictionPolicy(); log.info("{}", cacheConfiguration.getDiskStorePath()); log.info("{}", cacheConfiguration.getTimeToIdleSeconds()); log.info("{}", cacheConfiguration.getTimeToLiveSeconds()); log.info("{}", cacheConfiguration.getMaxElementsInMemory()); log.info("{}", cacheConfiguration.getMaxElementsOnDisk()); log.info("{}", cacheConfiguration.getName()); log.info("{}", policy.toString()); } public static void main(String[] args) throws Exception { new FirstCache(); } }
结果:
2018-09-09 15:08:14 [encache.FirstCache]-[INFO] null
2018-09-09 15:08:14 [encache.FirstCache]-[INFO] 60
2018-09-09 15:08:14 [encache.FirstCache]-[INFO] 60
2018-09-09 15:08:14 [encache.FirstCache]-[INFO] 2
2018-09-09 15:08:14 [encache.FirstCache]-[INFO] 2
2018-09-09 15:08:14 [encache.FirstCache]-[INFO] cache_test
2018-09-09 15:08:14 [encache.FirstCache]-[INFO] FIFO
3.动态的修改缓存的配置:
代码:
cacheConfiguration.setDiskStorePath(System.getProperty("java.io.tmpdir")); cacheConfiguration.setTimeToIdleSeconds(200); cacheConfiguration.setTimeToLiveSeconds(200); cacheConfiguration.setMaxElementsInMemory(4); cacheConfiguration.setMaxElementsOnDisk(4); cacheConfiguration.setName("cache_test_update"); cacheConfiguration.setMemoryStoreEvictionPolicy("CLOCK");
直接修改会报错:
Exception in thread "main" net.sf.ehcache.CacheException: Dynamic configuration changes are disabled for this cache
at net.sf.ehcache.config.CacheConfiguration.checkDynamicChange(CacheConfiguration.java:2711)
at net.sf.ehcache.config.CacheConfiguration.setDiskStorePath(CacheConfiguration.java:948)
at encache.FirstCache.<init>(FirstCache.java:35)
at encache.FirstCache.main(FirstCache.java:53)
官方解释:原因是上面encache.xml阻止了动态修改cache配置
Dynamic cache configurations can also be frozen to prevent future changes: Cache cache = manager.getCache("sampleCache"); cache.disableDynamicFeatures(); In ehcache.xml, you can disable dynamic configuration by setting the <ehcache> element's dynamicConfig attribute to "false".
解决办法在官方解释中说了,修改dynamicConfig属性为true
<ehcache updateCheck="false" dynamicConfig="true"> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="1000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="cache_test" maxElementsInMemory="2" eternal="false" timeToIdleSeconds="60" timeToLiveSeconds="60" maxElementsOnDisk="2" overflowToDisk="true" diskPersistent="false" memoryStoreEvictionPolicy="FIFO" /> </ehcache>
修改之后再次执行下main代码:
public FirstCache() { // 2.创建Cache Cache cache = cacheManager.getCache("cache_test"); CacheConfiguration cacheConfiguration = cache.getCacheConfiguration(); // 2.1获取满了之后的清除策略 MemoryStoreEvictionPolicy policy = cacheConfiguration.getMemoryStoreEvictionPolicy(); log.info("{}", cacheConfiguration.getDiskStorePath()); log.info("{}", cacheConfiguration.getTimeToIdleSeconds()); log.info("{}", cacheConfiguration.getTimeToLiveSeconds()); log.info("{}", cacheConfiguration.getMaxElementsInMemory()); log.info("{}", cacheConfiguration.getMaxElementsOnDisk()); log.info("{}", cacheConfiguration.getName()); log.info("{}", policy.toString()); log.info("==============================="); cacheConfiguration.setDiskStorePath(System.getProperty("java.io.tmpdir")); cacheConfiguration.setTimeToIdleSeconds(200); cacheConfiguration.setTimeToLiveSeconds(200); cacheConfiguration.setMaxElementsInMemory(4); cacheConfiguration.setMaxElementsOnDisk(4); cacheConfiguration.setName("cache_test_update"); cacheConfiguration.setMemoryStoreEvictionPolicy("CLOCK"); MemoryStoreEvictionPolicy policy2 = cacheConfiguration.getMemoryStoreEvictionPolicy(); log.info("{}", cacheConfiguration.getDiskStorePath()); log.info("{}", cacheConfiguration.getTimeToIdleSeconds()); log.info("{}", cacheConfiguration.getTimeToLiveSeconds()); log.info("{}", cacheConfiguration.getMaxElementsInMemory()); log.info("{}", cacheConfiguration.getMaxElementsOnDisk()); log.info("{}", cacheConfiguration.getName()); log.info("{}", policy2.toString()); }
结果:(修改生效)
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] null
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] 60
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] 60
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] 2
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] 2
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] cache_test
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] FIFO
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] ===============================
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] C:\Users\liqiang\AppData\Local\Temp\
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] 200
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] 200
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] 4
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] 4
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] cache_test_update
2018-09-09 15:18:46 [encache.FirstCache]-[INFO] CLOCK
4.测试上面配置的一些作用:
修改上面的配置:
<cache name="cache_test" maxElementsInMemory="2" eternal="false" timeToIdleSeconds="5" timeToLiveSeconds="5" maxElementsOnDisk="2" overflowToDisk="true" diskPersistent="false" memoryStoreEvictionPolicy="FIFO" />
(1)测试缓存的生存时间:
package encache; import java.util.Date; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheException; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; public class FirstCache { private static final Logger log = LoggerFactory.getLogger(FirstCache.class.getName()); public FirstCache() { // 1.创建CacheManager CacheManager cacheManager = new CacheManager();// 默认读取classpath目录下面的ehcache.xml // 2.创建Cache Cache cache = cacheManager.getCache("cache_test"); // 3.存取元素 cache.put(new Element("firstCache", "第一个缓存元素")); // 4.获取元素 Element element = cache.get("firstCache"); log.info("获取的缓存元素是:{}", element); long creationTime = element.getCreationTime(); long expirationTime = element.getExpirationTime(); log.info("creationTime: {}", new Date(creationTime)); log.info("expirationTime: {}", new Date(expirationTime)); log.info("diskStoreSize:{}", cache.getDiskStoreSize()); log.info("cacheSize: {}", cache.getKeys().size()); // 线程休眠6s,使缓存超时 try { // Thread.sleep(6*1000); TimeUnit.SECONDS.sleep(7); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 再次获取元素 try { Element element1 = cache.get("firstCache"); long creationTime1 = element1.getCreationTime(); long expirationTime1 = element1.getExpirationTime(); log.info("creationTime1: {}", new Date(creationTime1)); log.info("expirationTime1: {}", new Date(expirationTime1)); } catch (Exception e) { log.error("元素不存在"); } finally { log.info("diskStoreSize:{}", cache.getDiskStoreSize()); log.info("cacheSize: {}", cache.getKeys().size()); } } public static void main(String[] args) throws Exception { new FirstCache(); } }
查看日志:
2018-09-09 15:45:55 [net.sf.ehcache.CacheManager]-[DEBUG] Configuring ehcache from classpath.
2018-09-09 15:45:55 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from ehcache.xml found in the classpath: file:/E:/MavenEclipseWorkspace/encache/target/classes/ehcache.xml
2018-09-09 15:45:55 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from URL: file:/E:/MavenEclipseWorkspace/encache/target/classes/ehcache.xml
2018-09-09 15:45:55 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from InputStream
2018-09-09 15:45:55 [net.sf.ehcache.config.DiskStoreConfiguration]-[DEBUG] Disk Store Path: C:\Users\liqiang\AppData\Local\Temp\
2018-09-09 15:45:55 [net.sf.ehcache.util.PropertyUtil]-[DEBUG] propertiesString is null.
2018-09-09 15:45:55 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheManagerEventListenerFactory class specified. Skipping...
2018-09-09 15:45:56 [net.sf.ehcache.Cache]-[DEBUG] No BootstrapCacheLoaderFactory class specified. Skipping...
2018-09-09 15:45:56 [net.sf.ehcache.Cache]-[DEBUG] CacheWriter factory not configured. Skipping...
2018-09-09 15:45:56 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheExceptionHandlerFactory class specified. Skipping...
2018-09-09 15:45:56 [net.sf.ehcache.Cache]-[DEBUG] No BootstrapCacheLoaderFactory class specified. Skipping...
2018-09-09 15:45:56 [net.sf.ehcache.Cache]-[DEBUG] CacheWriter factory not configured. Skipping...
2018-09-09 15:45:56 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheExceptionHandlerFactory class specified. Skipping...
2018-09-09 15:45:56 [net.sf.ehcache.store.MemoryStore]-[DEBUG] Initialized net.sf.ehcache.store.MemoryStore for cache_test
2018-09-09 15:45:56 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file cache_test.data
2018-09-09 15:45:56 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file cache_test.index
2018-09-09 15:45:57 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Matching data file missing (or empty) for index file. Deleting index file C:\Users\liqiang\AppData\Local\Temp\cache_test.index
2018-09-09 15:45:57 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file cache_test.index
2018-09-09 15:45:57 [net.sf.ehcache.Cache]-[DEBUG] Initialised cache: cache_test
2018-09-09 15:45:57 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] CacheDecoratorFactory not configured. Skipping for 'cache_test'.
2018-09-09 15:45:57 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] CacheDecoratorFactory not configured for defaultCache. Skipping for 'cache_test'.
2018-09-09 15:45:57 [net.sf.ehcache.store.disk.Segment]-[DEBUG] put added 0 on heap
2018-09-09 15:45:57 [encache.FirstCache]-[INFO] 获取的缓存元素是:[ key = firstCache, value=第一个缓存元素, version=1, hitCount=1, CreationTime = 1536479157042, LastAccessTime = 1536479157054 ]
2018-09-09 15:45:57 [encache.FirstCache]-[INFO] creationTime: Sun Sep 09 15:45:57 CST 2018
2018-09-09 15:45:57 [encache.FirstCache]-[INFO] expirationTime: Sun Sep 09 15:46:02 CST 2018
2018-09-09 15:45:57 [encache.FirstCache]-[INFO] diskStoreSize:0
2018-09-09 15:45:57 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault removed 0 from heap
2018-09-09 15:45:57 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault added 0 on disk
2018-09-09 15:45:57 [encache.FirstCache]-[INFO] cacheSize: 1
2018-09-09 15:46:04 [net.sf.ehcache.store.disk.Segment]-[DEBUG] remove deleted 0 from heap
2018-09-09 15:46:04 [net.sf.ehcache.store.disk.Segment]-[DEBUG] remove deleted 0 from disk
2018-09-09 15:46:04 [encache.FirstCache]-[ERROR] 元素不存在
2018-09-09 15:46:04 [encache.FirstCache]-[INFO] diskStoreSize:0
2018-09-09 15:46:04 [encache.FirstCache]-[INFO] cacheSize: 0
也就是6s之后缓存会自动清除。缓存时间生效。
(2)测试缓存对象数量问题:
package encache; import java.util.Date; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheException; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; public class FirstCache { private static final Logger log = LoggerFactory.getLogger(FirstCache.class.getName()); public FirstCache() { // 1.创建CacheManager CacheManager cacheManager = new CacheManager();// 默认读取classpath目录下面的ehcache.xml // 2.创建Cache Cache cache = cacheManager.getCache("cache_test"); // 3.存取5个元素 cache.put(new Element("1", "第1个缓存元素")); cache.put(new Element("2", "第2个缓存元素")); cache.put(new Element("3", "第3个缓存元素")); cache.put(new Element("4", "第4个缓存元素")); cache.put(new Element("5", "第5个缓存元素")); cache.flush(); try { Thread.sleep(2 * 1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } log.info("diskStoreSize:{}", cache.getDiskStoreSize()); log.info("cacheSize: {}", cache.getKeys().size()); // 4.获取元素 for (Object key : cache.getKeys()) { log.info("ele:{}", cache.get(key).toString()); } } public static void main(String[] args) throws Exception { new FirstCache(); } }
结果:(只获取到最后添加的两个元素。FIFO策略也生效)
2018-09-09 16:17:11 [net.sf.ehcache.CacheManager]-[DEBUG] Configuring ehcache from classpath.
2018-09-09 16:17:11 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from ehcache.xml found in the classpath: file:/E:/MavenEclipseWorkspace/encache/target/classes/ehcache.xml
2018-09-09 16:17:11 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from URL: file:/E:/MavenEclipseWorkspace/encache/target/classes/ehcache.xml
2018-09-09 16:17:11 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from InputStream
2018-09-09 16:17:11 [net.sf.ehcache.config.DiskStoreConfiguration]-[DEBUG] Disk Store Path: C:\Users\liqiang\AppData\Local\Temp\
2018-09-09 16:17:11 [net.sf.ehcache.util.PropertyUtil]-[DEBUG] propertiesString is null.
2018-09-09 16:17:11 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheManagerEventListenerFactory class specified. Skipping...
2018-09-09 16:17:13 [net.sf.ehcache.Cache]-[DEBUG] No BootstrapCacheLoaderFactory class specified. Skipping...
2018-09-09 16:17:13 [net.sf.ehcache.Cache]-[DEBUG] CacheWriter factory not configured. Skipping...
2018-09-09 16:17:13 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheExceptionHandlerFactory class specified. Skipping...
2018-09-09 16:17:13 [net.sf.ehcache.Cache]-[DEBUG] No BootstrapCacheLoaderFactory class specified. Skipping...
2018-09-09 16:17:13 [net.sf.ehcache.Cache]-[DEBUG] CacheWriter factory not configured. Skipping...
2018-09-09 16:17:13 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheExceptionHandlerFactory class specified. Skipping...
2018-09-09 16:17:13 [net.sf.ehcache.store.MemoryStore]-[DEBUG] Initialized net.sf.ehcache.store.MemoryStore for cache_test
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Matching data file missing (or empty) for index file. Deleting index file C:\Users\liqiang\AppData\Local\Temp\cache_test.index
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file cache_test.index
2018-09-09 16:17:13 [net.sf.ehcache.Cache]-[DEBUG] Initialised cache: cache_test
2018-09-09 16:17:13 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] CacheDecoratorFactory not configured. Skipping for 'cache_test'.
2018-09-09 16:17:13 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] CacheDecoratorFactory not configured for defaultCache. Skipping for 'cache_test'.
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] put added 0 on heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] put added 0 on heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] put added 0 on heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] put added 0 on heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] put added 0 on heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault removed 0 from heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault added 0 on disk
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault removed 0 from heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault added 0 on disk
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault removed 0 from heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault added 0 on disk
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] evicted 0 from disk
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] evicted 0 from heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault removed 0 from heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault added 0 on disk
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] evicted 0 from disk
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] evicted 0 from heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault removed 0 from heap
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] fault added 0 on disk
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] evicted 0 from disk
2018-09-09 16:17:13 [net.sf.ehcache.store.disk.Segment]-[DEBUG] evicted 0 from heap
2018-09-09 16:17:15 [encache.FirstCache]-[INFO] diskStoreSize:2
2018-09-09 16:17:15 [encache.FirstCache]-[INFO] cacheSize: 2
2018-09-09 16:17:15 [encache.FirstCache]-[INFO] ele:[ key = 5, value=第5个缓存元素, version=1, hitCount=1, CreationTime = 1536481034000, LastAccessTime = 1536481035344 ]
2018-09-09 16:17:15 [encache.FirstCache]-[INFO] ele:[ key = 4, value=第4个缓存元素, version=1, hitCount=1, CreationTime = 1536481034000, LastAccessTime = 1536481035347 ]
3.defaultCache的作用
一直以为defaultCache的配置是会给我们创建一个cache,实际上是在程序中创建的cache会默认采用此配置。
在encache-core的包下面的ehcache-failsafe.xml的描述如下:
<!-- Mandatory Default Cache configuration. These settings will be applied to caches created programmtically using CacheManager.add(String cacheName) --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />
也就是程序中显示创建的Cache会默认使用defaultCache的配置。
package encache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.config.CacheConfiguration; import net.sf.ehcache.store.MemoryStoreEvictionPolicy; public class FirstCache { private static final Logger log = LoggerFactory.getLogger(FirstCache.class.getName()); public FirstCache() { // 1.创建CacheManager CacheManager cacheManager = CacheManager.create(); // 2.创建并且获取Cache cacheManager.addCache("dynamic_cache"); Cache cache = cacheManager.getCache("dynamic_cache"); CacheConfiguration cacheConfiguration = cache.getCacheConfiguration(); // 2.1获取满了之后的清除策略 MemoryStoreEvictionPolicy policy = cacheConfiguration.getMemoryStoreEvictionPolicy(); log.info("{}", cacheConfiguration.getDiskStorePath()); log.info("{}", cacheConfiguration.getTimeToIdleSeconds()); log.info("{}", cacheConfiguration.getTimeToLiveSeconds()); log.info("{}", cacheConfiguration.getMaxElementsInMemory()); log.info("{}", cacheConfiguration.getMaxElementsOnDisk()); log.info("{}", cacheConfiguration.getName()); log.info("{}", policy.toString()); } public static void main(String[] args) throws Exception { new FirstCache(); } }
结果:
2018-09-09 16:51:27 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from ehcache.xml found in the classpath: file:/E:/MavenEclipseWorkspace/encache/target/classes/ehcache.xml 2018-09-09 16:51:27 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from URL: file:/E:/MavenEclipseWorkspace/encache/target/classes/ehcache.xml 2018-09-09 16:51:27 [net.sf.ehcache.config.ConfigurationFactory]-[DEBUG] Configuring ehcache from InputStream 2018-09-09 16:51:27 [net.sf.ehcache.config.DiskStoreConfiguration]-[DEBUG] Disk Store Path: C:\Users\liqiang\AppData\Local\Temp\ 2018-09-09 16:51:27 [net.sf.ehcache.CacheManager]-[DEBUG] Creating new CacheManager with default config 2018-09-09 16:51:27 [net.sf.ehcache.util.PropertyUtil]-[DEBUG] propertiesString is null. 2018-09-09 16:51:27 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheManagerEventListenerFactory class specified. Skipping... 2018-09-09 16:51:29 [net.sf.ehcache.Cache]-[DEBUG] No BootstrapCacheLoaderFactory class specified. Skipping... 2018-09-09 16:51:29 [net.sf.ehcache.Cache]-[DEBUG] CacheWriter factory not configured. Skipping... 2018-09-09 16:51:29 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheExceptionHandlerFactory class specified. Skipping... 2018-09-09 16:51:29 [net.sf.ehcache.Cache]-[DEBUG] No BootstrapCacheLoaderFactory class specified. Skipping... 2018-09-09 16:51:29 [net.sf.ehcache.Cache]-[DEBUG] CacheWriter factory not configured. Skipping... 2018-09-09 16:51:29 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] No CacheExceptionHandlerFactory class specified. Skipping... 2018-09-09 16:51:29 [net.sf.ehcache.store.MemoryStore]-[DEBUG] Initialized net.sf.ehcache.store.MemoryStore for cache_test 2018-09-09 16:51:29 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Matching data file missing (or empty) for index file. Deleting index file C:\Users\liqiang\AppData\Local\Temp\cache_test.index 2018-09-09 16:51:29 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file cache_test.index 2018-09-09 16:51:29 [net.sf.ehcache.Cache]-[DEBUG] Initialised cache: cache_test 2018-09-09 16:51:29 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] CacheDecoratorFactory not configured. Skipping for 'cache_test'. 2018-09-09 16:51:29 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] CacheDecoratorFactory not configured for defaultCache. Skipping for 'cache_test'. 2018-09-09 16:51:29 [net.sf.ehcache.store.MemoryStore]-[DEBUG] Initialized net.sf.ehcache.store.MemoryStore for dynamic_cache 2018-09-09 16:51:29 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file dynamic_cache.data 2018-09-09 16:51:29 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file dynamic_cache.index 2018-09-09 16:51:29 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Matching data file missing (or empty) for index file. Deleting index file C:\Users\liqiang\AppData\Local\Temp\dynamic_cache.index 2018-09-09 16:51:29 [net.sf.ehcache.store.disk.DiskStorageFactory]-[DEBUG] Failed to delete file dynamic_cache.index 2018-09-09 16:51:29 [net.sf.ehcache.Cache]-[DEBUG] Initialised cache: dynamic_cache 2018-09-09 16:51:29 [net.sf.ehcache.config.ConfigurationHelper]-[DEBUG] CacheDecoratorFactory not configured for defaultCache. Skipping for 'dynamic_cache'. 2018-09-09 16:51:29 [encache.FirstCache]-[INFO] null 2018-09-09 16:51:29 [encache.FirstCache]-[INFO] 120 2018-09-09 16:51:29 [encache.FirstCache]-[INFO] 120 2018-09-09 16:51:29 [encache.FirstCache]-[INFO] 1000 2018-09-09 16:51:29 [encache.FirstCache]-[INFO] 0 2018-09-09 16:51:29 [encache.FirstCache]-[INFO] dynamic_cache 2018-09-09 16:51:29 [encache.FirstCache]-[INFO] LRU
4.encache原码分析:
CacheManager
一个普通的class,里面包含管理cache的信息
public class CacheManager { /** * Default name if not specified in the configuration/ */ public static final String DEFAULT_NAME = "__DEFAULT__"; /** * Threshold, in percent of the available heap, above which the CacheManager will warn if the configured memory */ public static final double ON_HEAP_THRESHOLD = 0.8; /** * Keeps track of all known CacheManagers. Used to check on conflicts. * CacheManagers should remove themselves from this list during shut down. */ public static final List<CacheManager> ALL_CACHE_MANAGERS = new CopyOnWriteArrayList<CacheManager>(); /** * System property to enable creation of a shutdown hook for CacheManager. */ public static final String ENABLE_SHUTDOWN_HOOK_PROPERTY = "net.sf.ehcache.enableShutdownHook"; private static final Logger LOG = LoggerFactory.getLogger(CacheManager.class); /** * Update check interval - one week in milliseconds */ private static final long EVERY_WEEK = 7 * 24 * 60 * 60 * 1000; private static final long DELAY_UPDATE_CHECK = 1000; private static volatile CacheManager singleton; private static final MBeanRegistrationProviderFactory MBEAN_REGISTRATION_PROVIDER_FACTORY = new MBeanRegistrationProviderFactoryImpl(); private static final String NO_DEFAULT_CACHE_ERROR_MSG = "Caches cannot be added by name when default cache config is not specified" + " in the config. Please add a default cache config in the configuration."; private static final Map<String, CacheManager> CACHE_MANAGERS_MAP = new HashMap<String, CacheManager>(); private static final IdentityHashMap<CacheManager, String> CACHE_MANAGERS_REVERSE_MAP = new IdentityHashMap<CacheManager, String>(); protected volatile Status status; protected final Map<String, CacheManagerPeerProvider> cacheManagerPeerProviders = new ConcurrentHashMap<String, CacheManagerPeerProvider>(); protected final Map<String, CacheManagerPeerListener> cacheManagerPeerListeners = new ConcurrentHashMap<String, CacheManagerPeerListener>(); protected final CacheManagerEventListenerRegistry cacheManagerEventListenerRegistry = new CacheManagerEventListenerRegistry(); protected Thread shutdownHook; private final ConcurrentMap<String, Ehcache> ehcaches = new ConcurrentHashMap<String, Ehcache>();
ehcaches里面存放的是一个一个的cache。
Cache:
public class Cache implements InternalEhcache, StoreListener { public static final String DEFAULT_CACHE_NAME = "default"; public static final String NET_SF_EHCACHE_DISABLED = "net.sf.ehcache.disabled"; public static final String NET_SF_EHCACHE_USE_CLASSIC_LRU = "net.sf.ehcache.use.classic.lru"; public static final long DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS = CacheConfiguration.DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS; public static final String OFF_HEAP_STORE_CLASSNAME = "net.sf.ehcache.store.offheap.OffHeapStore"; private static final Logger LOG = LoggerFactory.getLogger(Cache.class.getName());
private volatile Store compoundStore; 用于存放真正的元素。
Element:
一个实现serializable和clonable的普通类,里面有key和value以及一些其他信息:
public class Element implements Serializable, Cloneable { private static final long serialVersionUID = 1098572221246444544L; private static final Logger LOG = LoggerFactory.getLogger(Element.class.getName()); private static final AtomicLongFieldUpdater<Element> HIT_COUNT_UPDATER = AtomicLongFieldUpdater.newUpdater(Element.class, "hitCount"); private static final boolean ELEMENT_VERSION_AUTO = Boolean.getBoolean("net.sf.ehcache.element.version.auto"); static { if (ELEMENT_VERSION_AUTO) { LOG.warn("Note that net.sf.ehcache.element.version.auto is set and user provided version will not be honored"); } } @IgnoreSizeOf private final Object key; private final Object value; private volatile long version; private volatile long hitCount; private volatile int timeToLive = Integer.MIN_VALUE; private volatile int timeToIdle = Integer.MIN_VALUE; private transient volatile ElementEvictionData elementEvictionData; private volatile long lastUpdateTime; private volatile boolean cacheDefaultLifespan = true;
Encache也可以进行集群等高级操作,待用到的时候查阅API即可。encache是新开一个线程进行缓存管理,JVM不停此线程也不会停止。
补充:在一个JVM如果创建两个名字相同的cache,则会报错,如下:
package encache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.ehcache.CacheManager; public class SecondCache { private static final Logger log = LoggerFactory.getLogger(SecondCache.class.getName()); public static void main(String[] args) throws Exception { // 1.创建CacheManager final CacheManager cacheManager = CacheManager.create(); new Thread(new Runnable() { @Override public void run() { cacheManager.addCache("dynamic_cache"); } }).start(); new Thread(new Runnable() { @Override public void run() { cacheManager.addCache("dynamic_cache"); } }).start(); } }
结果:
Exception in thread "Thread-1" net.sf.ehcache.ObjectExistsException: Cache dynamic_cache already exists
at net.sf.ehcache.CacheManager.addCacheNoCheck(CacheManager.java:1294)
at net.sf.ehcache.CacheManager.addCache(CacheManager.java:1184)
at net.sf.ehcache.CacheManager.addCache(CacheManager.java:1126)
at encache.SecondCache$1.run(SecondCache.java:17)
at java.lang.Thread.run(Thread.java:745)
补充:Element有一个构造方法可以指定缓存的时间等参数
package encache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; public class FirstCache { private static final Logger log = LoggerFactory.getLogger(FirstCache.class.getName()); public FirstCache() { // 1.创建CacheManager CacheManager cacheManager = new CacheManager();// 默认读取classpath目录下面的ehcache.xml // 2.创建Cache Cache cache = cacheManager.getCache("cache_test"); // 3.添加元素 cache.put(new Element("key", "value", false, 0, 12)); // 4.休眠5秒钟获取元素 try { Thread.sleep(5 * 1000); } catch (InterruptedException e) { } Element element = cache.get("key"); System.out.println(element); // 4.休眠13秒钟获取元素 try { Thread.sleep(13 * 1000); } catch (InterruptedException e) { } // 4.获取元素 Element element2 = cache.get("key"); System.out.println(element2); } public static void main(String[] args) throws Exception { new FirstCache(); } }
结果:
[ key = key, value=value, version=0, hitCount=1, CreationTime = 1544537618418, LastAccessTime = 1544537623428 ]
null
补充:在学习了多线程之后对ehcache缓存进行的实验多线程环境下
package encache; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; public class SecondCache { private static final Logger log = LoggerFactory.getLogger(SecondCache.class.getName()); public static void main(String[] args) throws Exception { // 1.创建CacheManager final CacheManager cacheManager = CacheManager.create(); // 开启线程创建cache new Thread(new Runnable() { @Override public void run() { log.info("添加缓存->{},threadName->{}", "dynamic_cache", Thread.currentThread().getName()); cacheManager.addCache("dynamic_cache"); } }, "A").start(); // 添加元素 Thread.sleep(1 * 1000); new Thread(new Runnable() { @Override public void run() { Cache cache = cacheManager.getCache("dynamic_cache"); for (int i = 0; i < 5; i++) { Map<String, Object> cacheEle = new HashMap<>(); cacheEle.put("" + i, "第" + i + "个元素"); log.info("添加缓存元素->{},threadName->{}", cacheEle, Thread.currentThread().getName()); cache.put(new Element(i + "key", cacheEle)); } // 覆盖第二个元素 Map<String, Object> cacheEle = new HashMap<>(); cacheEle.put("" + 2, "第" + 22222 + "个元素"); cache.put(new Element(2 + "key", cacheEle)); log.info("覆盖缓存元素->{},threadName->{}", 2 + "key", Thread.currentThread().getName()); cache.flush(); } }, "B").start(); // 访问元素 Thread.sleep(1 * 1000); new Thread(new Runnable() { @Override public void run() { Cache cache = cacheManager.getCache("dynamic_cache"); for (Object key : cache.getKeys()) { log.info("获取缓存元素key->{},value->{},threadName->{}", new Object[] { key, (Map) cache.get(key).getObjectValue(), Thread.currentThread().getName() }); } } }, "C").start(); } }
结果:
2018-12-11 21:53:10 [encache.SecondCache]-[INFO] 添加缓存->dynamic_cache,threadName->A
2018-12-11 21:53:11 [encache.SecondCache]-[INFO] 添加缓存元素->{0=第0个元素},threadName->B
2018-12-11 21:53:11 [encache.SecondCache]-[INFO] 添加缓存元素->{1=第1个元素},threadName->B
2018-12-11 21:53:11 [encache.SecondCache]-[INFO] 添加缓存元素->{2=第2个元素},threadName->B
2018-12-11 21:53:11 [encache.SecondCache]-[INFO] 添加缓存元素->{3=第3个元素},threadName->B
2018-12-11 21:53:11 [encache.SecondCache]-[INFO] 添加缓存元素->{4=第4个元素},threadName->B
2018-12-11 21:53:11 [encache.SecondCache]-[INFO] 覆盖缓存元素->2key,threadName->B
2018-12-11 21:53:12 [encache.SecondCache]-[INFO] 获取缓存元素key->4key,value->{4=第4个元素},threadName->C
2018-12-11 21:53:12 [encache.SecondCache]-[INFO] 获取缓存元素key->1key,value->{1=第1个元素},threadName->C
2018-12-11 21:53:12 [encache.SecondCache]-[INFO] 获取缓存元素key->3key,value->{3=第3个元素},threadName->C
2018-12-11 21:53:12 [encache.SecondCache]-[INFO] 获取缓存元素key->0key,value->{0=第0个元素},threadName->C
2018-12-11 21:53:12 [encache.SecondCache]-[INFO] 获取缓存元素key->2key,value->{2=第22222个元素},threadName->C
补充:自己封装的一个工具类以及简单的测试:
package ehcache; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import net.sf.ehcache.config.CacheConfiguration; import net.sf.ehcache.store.MemoryStoreEvictionPolicy; public class EhcacheUtils { public static final String CACHE_NAME1 = "cache1"; public static final String CACHE_NAME2 = "cache2"; public static final int CACHE_ONE_HOUR = 1 * 60 * 60; public static final int CACHE_ONE_DAY = 24 * 60 * 60; private static CacheManager cacheManager = CacheManager.create(); // 静态代码块创建缓存 static { cacheManager.addCache(CACHE_NAME1); cacheManager.addCache(CACHE_NAME2); initCacheSettings(cacheManager.getCache(CACHE_NAME1)); initCacheSettings(cacheManager.getCache(CACHE_NAME2)); } private static void initCacheSettings(Cache cache) { CacheConfiguration cacheConfiguration = cache.getCacheConfiguration(); cacheConfiguration.setTimeToIdleSeconds(8 * 60 * 60); cacheConfiguration.setTimeToLiveSeconds(24 * 60 * 60); // cacheConfiguration.setMaxElementsInMemory(4); // cacheConfiguration.setMaxElementsOnDisk(4); // cacheConfiguration.setName("cache_test_update"); cacheConfiguration.setMemoryStoreEvictionPolicy("CLOCK"); } private EhcacheUtils() { } // 1.增加元素 /** * 向指定的缓存中增加元素 * * @param cacheName * 缓存名称 * @param key * 缓存的key * @param value * 缓存d值 * @param seconds * 缓存的时间(秒) * @param override * 如果存在是否覆盖 * @return */ public static boolean addCache(String cacheName, String key, Object value, int seconds, boolean override) { try { Cache cache = cacheManager.getCache(cacheName); Object tmpValue = getValueByCacheKey(cacheName, key); if (tmpValue != null) { if (!override) { return true; } } cache.put(new Element(key, value, false, 0, seconds)); cache.flush(); return true; } catch (Exception e) { return false; } } // 2.删除元素 // 2.1删除单个元素 /** * 删除单个元素 * * @param cacheName * 缓存的名称 * @param key * 缓存的key * @return */ public static boolean removeCacheByKey(String cacheName, String key) { try { Cache cache = cacheManager.getCache(cacheName); cache.remove(key); return true; } catch (Exception e) { return false; } } // 2.2删除全部元素 /** * 删除所有元素 * * @param cacheName * 缓存名称 * @return */ public static boolean removeAllByCacheName(String cacheName) { try { Cache cache = cacheManager.getCache(cacheName); cache.removeAll(); return true; } catch (Exception e) { return false; } } // 3.获取元素 // 3.1获取单个元素 /** * 获取单个元素 * * @param cacheName * 缓存名称 * @param key * 缓存的key * @return */ public static Object getValueByCacheKey(String cacheName, String key) { try { Cache cache = cacheManager.getCache(cacheName); Element element = cache.get(key); return element == null ? null : element.getObjectValue(); } catch (Exception e) { return null; } } // 3.1获取全部元素 /** * 获取所有缓存d元素 * * @param cacheName * 缓存的名称 * @return */ public static List<Object> getAllValuesByCacheName(String cacheName) { List<Object> result = new ArrayList<Object>(); try { Cache cache = cacheManager.getCache(cacheName); for (Object key : cache.getKeys()) { Element element = cache.get(key); result.add(element.getObjectValue()); } return result; } catch (Exception e) { return result; } } // 4.获取配置 public static Map<String, String> getConfigurations(String cacheName) { Map<String, String> results = new HashMap<String, String>(); Cache cache = cacheManager.getCache(cacheName); CacheConfiguration cacheConfiguration = cache.getCacheConfiguration(); MemoryStoreEvictionPolicy policy = cacheConfiguration.getMemoryStoreEvictionPolicy(); results.put("timeToIdleSeconds", String.valueOf(cacheConfiguration.getTimeToIdleSeconds())); results.put("timeToLiveSeconds", String.valueOf(cacheConfiguration.getTimeToLiveSeconds())); results.put("maxElementsInMemory", String.valueOf(cacheConfiguration.getMaxElementsInMemory())); results.put("policy", policy.toString()); return results; } }
ehcache.xml
<ehcache updateCheck="false" dynamicConfig="true"> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="1000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache>
测试代码:
List<String> cache1 = new ArrayList<>(); cache1.add("111"); cache1.add("222"); EhcacheUtils.addCache(EhcacheUtils.CACHE_NAME1, "cache1", cache1, EhcacheUtils.CACHE_ONE_HOUR, false); String cache2 = "cache2"; EhcacheUtils.addCache(EhcacheUtils.CACHE_NAME1, "cache2", cache2, EhcacheUtils.CACHE_ONE_HOUR, false); Map cache3 = new HashMap(); cache3.put("1", "111222"); cache3.put("2", "111222333"); EhcacheUtils.addCache(EhcacheUtils.CACHE_NAME1, "cache3", cache3, EhcacheUtils.CACHE_ONE_HOUR, false); Map valueByCacheKey = (Map) EhcacheUtils.getValueByCacheKey(EhcacheUtils.CACHE_NAME1, "cache3"); System.out.println(valueByCacheKey); EhcacheUtils.removeCacheByKey(EhcacheUtils.CACHE_NAME1, "cache2"); List<Object> allValuesByCacheName = EhcacheUtils.getAllValuesByCacheName(EhcacheUtils.CACHE_NAME1); for (Object obj : allValuesByCacheName) { System.out.println(obj); } Map<String, String> configurations = EhcacheUtils.getConfigurations(EhcacheUtils.CACHE_NAME1); System.out.println(configurations);
结果:(线程也没有停止)
采用JVisualVM查看线程信息: (主线程结束了,但是仍然有ehcache创建的用户线程,有3个用户线程----创建CacheManager的时候会创建一个守护线程Statisxxxx,每次创建一个cache的时候也会创建一个用户线程 cacheName.data)
源代码跟踪解释线程:
(1)在 调用CacheManager cacheManager = CacheManager.create(); 创建CacheManager的时候创建一个守护线程Statistics thread-_default_-1 统计线程
public CacheManager(String configurationFileName) throws CacheException { status = Status.STATUS_UNINITIALISED; init(null, configurationFileName, null, null); }
init中调用doInit(...)
doInit(...)创建线程(用到线程池进行周期性调用---此线程是一个守护线程)
statisticsExecutor = Executors.newScheduledThreadPool( Integer.getInteger("net.sf.ehcache.CacheManager.statisticsExecutor.poolSize", 1) , new ThreadFactory() { private AtomicInteger cnt = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, "Statistics Thread-" + getName() + "-" + cnt.incrementAndGet()); t.setDaemon(true); return t; } });
(2)在调用cacheManager.addCache("cache1");的时候创建一个用户线程:cache1.data (所以主线程结束,此线程也没有结束,进程也没有结束)
...这个代码暂时没有根出来,只是根到调用此方法后创建了一个用户线程
最完美的就是再写一个key生成器,KeyGenerator可以参考下面代码:
package cn.xm.jwxt.utils; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * @Author: qlq * @Description * @Date: 22:49 2018/3/25 */ public class KeyGenerator implements org.springframework.cache.interceptor.KeyGenerator { @Override public Object generate(Object o, Method method, Object... params) { //规定 本类名+方法名+参数名 为key StringBuilder sb = new StringBuilder(); sb.append(o.getClass().getName()); sb.append(method.getName()); for (Object param : params) { sb.append(param.toString()); } return sb.toString(); } }