緩存的名字是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(); } }