ehcahe的介绍
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。
主要的特性有
- 快速
- 简单
- 多种缓存策略
- 缓存数据有两级:内存和磁盘,因此无需担心容量问题
- 缓存数据会在虚拟机重启的过程中写入磁盘
- 可以通过RMI、可插入API等方式进行分布式缓存
- 具有缓存和缓存管理器的侦听接口
- 支持多缓存管理器实例,以及一个实例的多个缓存区域
- 提供Hibernate的缓存实现
ehcahe依赖的jar包
ehcache.jar
commons-logging-1.1.1.jar
backport-util-concurrent.jar
获取缓存对象
创建缓存管理器
从缓存管理器中获取缓存对象,进而操作缓存
// 1. 创建缓存管理器
CacheManager cacheManager = CacheManager.getInstance();
// 2. 获取缓存对象
cache = cacheManager.getCache("cacheName");
跟踪源码CacheManager.java
public static CacheManager getInstance() throws CacheException {
return create();
}
public static CacheManager create() throws CacheException {
// 单例模式
synchronized(CacheManager.class) {
if (singleton == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating new CacheManager with default config");
}
// 初始化
singleton = new CacheManager();
} else if (LOG.isDebugEnabled()) {
LOG.debug("Attempting to create an existing singleton. Existing singleton returned.");
}
return singleton;
}
}
public CacheManager() throws CacheException {
this.status = Status.STATUS_UNINITIALISED;
this.init((Configuration)null, (String)null, (URL)null, (InputStream)null);
}
默认这4个参数都为null
private void init(Configuration configuration, String configurationFileName, URL configurationURL, InputStream configurationInputStream) {
Configuration localConfiguration = configuration;
if (configuration == null) {
localConfiguration = this.parseConfiguration(configurationFileName, configurationURL, configurationInputStream);
} else {
configuration.setSource("Programmatically configured.");
}
ConfigurationHelper configurationHelper = new ConfigurationHelper(this, localConfiguration);
this.configure(configurationHelper);
this.status = Status.STATUS_ALIVE;
if (this.cacheManagerPeerProvider != null) {
this.cacheManagerPeerProvider.init();
}
this.cacheManagerEventListenerRegistry.init();
this.addShutdownHookIfRequired();
this.addConfiguredCaches(configurationHelper);
}
关注localConfiguration = this.parseConfiguration(configurationFileName, configurationURL, configurationInputStream);
进入该方法,会执行configuration = ConfigurationFactory.parseConfiguration();
public static Configuration parseConfiguration() throws CacheException {
ClassLoader standardClassloader = ClassLoaderUtil.getStandardClassLoader();
URL url = null;
if (standardClassloader != null) {
url = standardClassloader.getResource("/ehcache.xml");
}
if (url == null) {
url = ConfigurationFactory.class.getResource("/ehcache.xml");
}
if (url != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Configuring ehcache from ehcache.xml found in the classpath: " + url);
}
} else {
url = ConfigurationFactory.class.getResource("/ehcache-failsafe.xml");
if (LOG.isWarnEnabled()) {
LOG.warn("No configuration found. Configuring ehcache from ehcache-failsafe.xml found in the classpath: " + url);
}
}
return parseConfiguration(url);
}
可以看到,回去根目录中寻找ehcache配置文件ehcache.xml
,如果找不到会通过找到ehcache-failsafe.xml
"(ehcache的jar包内置的文件)执行快速失败
No configuration found. Configuring ehcache from ehcache-failsafe.xml found in the classpath: jar:file:/D:/java-lib/ehcache.jar!/ehcache-failsafe.xml
此时缓存管理器中没有缓存对象,所以必须要配置ehcache.xml
配置文件ehcache.xml
<?xml version="1.0" encoding="GBK"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//127.0.0.1:40002/SimplePageCachingFilter" />
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=127.0.0.1,port=40001, socketTimeoutMillis=12000" />
<!-- 磁盘地址 C:\Users\YWX558~1\AppData\Local\Temp\-->
<!-- System.getProperty("java.io.tmpdir") -->
<diskStore path="java.io.tmpdir" />
<!--
配置自定义缓存
defaultCache:默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理
maxElementsInMemory:缓存中允许创建的最大对象数
maxElementsOnDisk:硬盘中最大缓存对象数,若是0表示无穷大
eternal:缓存中对象是否为永久的,如果是,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false
overflowToDisk:true表示当内存缓存的对象数目达到了
maxElementsInMemory界限后,会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行。
diskSpoolBufferSizeMB:磁盘缓存区大小,默认为30MB。每个Cache都应该有自己的一个缓存区。
diskPersistent:是否缓存虚拟机重启期数据,是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名 为cache名称,后缀名为index的文件,
这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存,要想把 cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认为120秒
timeToIdleSeconds:缓存数据的钝化时间,也就是在一个元素消亡之前,两次访问时间的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是 0 就意味着元素可以停顿无穷长的时间。
timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
-->
<defaultCache maxElementsInMemory="10000" eternal="false"
overflowToDisk="true" timeToIdleSeconds="500" timeToLiveSeconds="1000"
diskPersistent="false" diskExpiryThreadIntervalSeconds="120">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=true, replicateRemovals=true" />
</defaultCache>
<!--
cache:为指定名称的对象进行缓存的特殊配置
name:指定对象的完整名
缓存的3 种清空策略
1、FIFO ,first in first out (先进先出).
2、LFU , Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。
3、LRU ,Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
-->
<cache name="SimplePageCachingFilter"
maxElementsInMemory="10000"
maxElementsOnDisk="10000"
eternal="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="20"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="120"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
</cache>
</ehcache>
测试
public static void main(String[] args) {
// ClassLoader standardClassloader = ClassLoaderUtil.getStandardClassLoader();
// URL url = null;
// if(standardClassloader != null)
// url = standardClassloader.getResource("/ehcache.xml");
// System.out.println("url==="+url);
// System.out.println("url1==="+ConfigurationFactory.class.getResource("/ehcache.xml"));
// System.out.println("url2==="+ClassLoader.getSystemResource("ehcache.xml"));
// System.out.println("url3==="+ClassLoader.getSystemClassLoader().getResource("ehcache.xml"));
// 1. 创建缓存管理器
CacheManager cacheManager = CacheManager.getInstance();
Cache cache = null;
// 2. 获取缓存对象
cache = cacheManager.getCache("SimplePageCachingFilter");
System.out.println("cache="+cache);
// 3. 创建元素
Element element = new Element("key1", "value1");
cache.put(element);
element = new Element("key2", "value2");
cache.put(element);
// 5. 获取缓存
Element value = cache.get("key1");
System.out.println("key1="+value);
System.out.println("key1的值="+value.getObjectValue());
System.out.print("\n");
System.out.println("开始循环所有key");
cache.getKeys().forEach(System.out::println);
// 6. 删除元素
cache.remove("key1");
// 7. 刷新缓存,存储到磁盘
cache.flush();
// 8. 关闭缓存管理器
cacheManager.shutdown();
System.out.println(System.getProperty("java.io.tmpdir"));
}
控制台打印
cache=[ name = SimplePageCachingFilter status = STATUS_ALIVE eternal = false overflowToDisk = true maxElementsInMemory = 10000 maxElementsOnDisk = 10000 memoryStoreEvictionPolicy = LFU timeToLiveSeconds = 0 timeToIdleSeconds = 0 diskPersistent = true diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator hitCount = 0 memoryStoreHitCount = 0 diskStoreHitCount = 0 missCountNotFound = 0 missCountExpired = 0 ]
key1=[ key = key1, value=value1, version=1, hitCount=1, CreationTime = 1552361013985, LastAccessTime = 1552361013985 ]
key1的值=value1
开始循环所有key
key1
key2
C:\Users\YWX558~1\AppData\Local\Temp\