一、pom.xml 依赖项
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.8.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.7</version> </dependency> </dependencies>
二、ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- 参数的含义分别是: a.maxElementInMemory表示该缓存中可以放置多少个对象,此处为1000个,根据内存的多少可以配置 b.eternal表示是否设置这些放入二级缓存的数据对象为永久的(即放入即保存,不再清除)一般都为false c.timeToIdleSeconds=120表示如果120秒内,放入的对象没有被再次访问到,就清除出去 d.timeToLiveSeconds=120表示对象在缓存中存活的时间,一个对象进入到本缓存中120秒后,就会自动被清除(一般 设置的时间会比timeToIdleSeconds时间长),设置此属性是为了让更多活跃的对象进入到缓存中来。 e.overflowToDisk="true"表示如果活跃对象已经超出maxElementInMemory设置的最大值时,超出的对象要被写入到硬盘上保存下来,用于缓解活跃用户较多的情况。 f.Ehcache有一个后台线程专门做Ellment失效监测以及清除工作。设置线程运行间隔时间,可通过设置diskExpiryThreadIntervalSeconds属性来完成,此值不宜设置过低,否则会导致清理线程占用大量CPU资源。默认值是120秒。 --> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true"> <diskStore path="java.io.tmpdir" /> <defaultCache maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap" /> </defaultCache> <cache name="sampleCache1" maxEntriesLocalHeap="10000" maxEntriesLocalDisk="1000" eternal="false" diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <persistence strategy="localTempSwap" /> </cache> <cache name="sampleCache2" maxEntriesLocalHeap="1000" eternal="true" memoryStoreEvictionPolicy="FIFO" /> </ehcache>
三、示例代码
package com.cn.fangxin.ehcache.test; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.junit.*; public class TestEhcache { @Test public void testEhcachae() throws InterruptedException { CacheManager manager = CacheManager.create(); // 取出所有的cacheName String names[] = manager.getCacheNames(); System.out.println("----all cache names----"); for (int i = 0; i < names.length; i++) { System.out.println(names[i]); } System.out.println("----------------------"); // 得到一个cache对象 Cache cache1 = manager.getCache(names[0]); // 向cache1对象里添加缓存 cache1.put(new Element("key1", "values1")); Element element = cache1.get("key1"); // 读取缓存 System.out.println("key1 \t= " + element.getObjectValue()); // 手动创建一个cache(ehcache里必须有defaultCache存在,"test"可以换成任何值) Cache cache2 = new Cache("test", 1, true, false, 2, 3); manager.addCache(cache2); cache2.put(new Element("jimmy", "菩提树下的杨过")); // 故意停1.5秒,以验证是否过期 Thread.sleep(1500); Element eleJimmy = cache2.get("jimmy"); //1.5s < 2s 不会过期 if (eleJimmy != null) { System.out.println("jimmy \t= " + eleJimmy.getObjectValue()); } //再等上0.5s, 总时长:1.5 + 0.5 >= min(2,3),过期 Thread.sleep(500); eleJimmy = cache2.get("jimmy"); if (eleJimmy != null) { System.out.println("jimmy \t= " + eleJimmy.getObjectValue()); } // 取出一个不存在的缓存项 System.out.println("fake \t= " + cache2.get("fake")); manager.shutdown(); } }
运行结果:
----all cache names----
sampleCache2
sampleCache1
----------------------
key1 = values1
jimmy = 菩提树下的杨过
fake = null
四、关于timeToLiveSeconds、timeToIdleSeconds
这二个参数直接影响缓存项的过期时间,看文档说明基本上没啥用,直接看net.sf.ehcache.Element源码的片段:
/** * The amount of time for the element to live, in seconds. 0 indicates unlimited. */ private volatile int timeToLive = Integer.MIN_VALUE; /** * The amount of time for the element to idle, in seconds. 0 indicates unlimited. */ private volatile int timeToIdle = Integer.MIN_VALUE; /** * Sets time to Live * <P/> * Value must be a positive integer, 0 means infinite time to live. * <P/> * If calling this method with 0 as the parameter, consider using {@link #setEternal(boolean)} * or make sure you also explicitly call {@link #setTimeToIdle(int)}. * * @param timeToLiveSeconds the number of seconds to live */ public void setTimeToLive(final int timeToLiveSeconds) { if (timeToLiveSeconds < 0) { throw new IllegalArgumentException("timeToLive can't be negative"); } this.cacheDefaultLifespan = false; this.timeToLive = timeToLiveSeconds; } /** * Sets time to idle * <P/> * Value must be a positive integer, 0 means infinite time to idle. * <P/> * If calling this method with 0 as the parameter, consider using {@link #setEternal(boolean)} * or make sure you also explicitly call {@link #setTimeToLive(int)}. * * @param timeToIdleSeconds the number of seconds to idle */ public void setTimeToIdle(final int timeToIdleSeconds) { if (timeToIdleSeconds < 0) { throw new IllegalArgumentException("timeToIdle can't be negative"); } this.cacheDefaultLifespan = false; this.timeToIdle = timeToIdleSeconds; } /** * An element is expired if the expiration time as given by {@link #getExpirationTime()} is in the past. * * @return true if the Element is expired, otherwise false. If no lifespan has been set for the Element it is * considered not able to expire. * @see #getExpirationTime() */ public boolean isExpired() { if (!isLifespanSet() || isEternal()) { return false; } long now = System.currentTimeMillis(); long expirationTime = getExpirationTime(); return now > expirationTime; } /** * An element is expired if the expiration time as given by {@link #getExpirationTime()} is in the past. * <p> * This method in addition propogates the default TTI/TTL values of the supplied cache into this element. * * @param config config to take default parameters from * @return true if the Element is expired, otherwise false. If no lifespan has been set for the Element it is * considered not able to expire. * @see #getExpirationTime() */ public boolean isExpired(CacheConfiguration config) { if (cacheDefaultLifespan) { if (config.isEternal()) { timeToIdle = 0; timeToLive = 0; } else { timeToIdle = TimeUtil.convertTimeToInt(config.getTimeToIdleSeconds()); timeToLive = TimeUtil.convertTimeToInt(config.getTimeToLiveSeconds()); } } return isExpired(); } /** * Returns the expiration time based on time to live. If this element also has a time to idle setting, the expiry * time will vary depending on whether the element is accessed. * * @return the time to expiration */ public long getExpirationTime() { if (!isLifespanSet() || isEternal()) { return Long.MAX_VALUE; } long expirationTime = 0; long ttlExpiry = creationTime + TimeUtil.toMillis(getTimeToLive()); long mostRecentTime = Math.max(creationTime, lastAccessTime); long ttiExpiry = mostRecentTime + TimeUtil.toMillis(getTimeToIdle()); if (getTimeToLive() != 0 && (getTimeToIdle() == 0 || lastAccessTime == 0)) { expirationTime = ttlExpiry; } else if (getTimeToLive() == 0) { expirationTime = ttiExpiry; } else { expirationTime = Math.min(ttlExpiry, ttiExpiry); } return expirationTime; } /** * @return true if the element is eternal */ public boolean isEternal() { return (0 == timeToIdle) && (0 == timeToLive); } /** * Sets whether the element is eternal. * * @param eternal */ public void setEternal(final boolean eternal) { if (eternal) { this.cacheDefaultLifespan = false; this.timeToIdle = 0; this.timeToLive = 0; } else if (isEternal()) { this.cacheDefaultLifespan = false; this.timeToIdle = Integer.MIN_VALUE; this.timeToLive = Integer.MIN_VALUE; } } /** * Whether any combination of eternal, TTL or TTI has been set. * * @return true if set. */ public boolean isLifespanSet() { return this.timeToIdle != Integer.MIN_VALUE || this.timeToLive != Integer.MIN_VALUE; } /** * @return the time to live, in seconds */ public int getTimeToLive() { if (Integer.MIN_VALUE == timeToLive) { return 0; } else { return timeToLive; } } /** * @return the time to idle, in seconds */ public int getTimeToIdle() { if (Integer.MIN_VALUE == timeToIdle) { return 0; } else { return timeToIdle; } } /** * Set the default parameters of this element - those from its enclosing cache. * @param tti TTI in seconds * @param ttl TTL in seconds * @param eternal <code>true</code> if the element is eternal. */ protected void setLifespanDefaults(int tti, int ttl, boolean eternal) { if (eternal) { this.timeToIdle = 0; this.timeToLive = 0; } else if (isEternal()) { this.timeToIdle = Integer.MIN_VALUE; this.timeToLive = Integer.MIN_VALUE; } else { timeToIdle = tti; timeToLive = ttl; } }
结论:
a) timeToIdleSeconds(空闲时间)、timeToLiveSeconds(生存时间)都设置为0时,表示不过期
b) 如果只有timeToLiveSeconds设置>0的值,则Element的过期时间为 timeToLiveSeconds
c) 如果只有timeToIdleSeconds设置>0的值,则Element的过期时间为 (上次访问时间+timeToIdleSeconds),说得更通俗点,上次get过了,现在又想get,若二次get的时间间隔>timeToIdleSeconds,则过期(即:最后一次get出来为null)
d) 如果timeToLiveSeconds、timeToIdleSeconds都有>0的值,则最终过期时间为 b),c)规则综合起来,取二者的最小值
测试1:
@Test public void testTimeToIdleSeconds() throws InterruptedException { CacheManager manager = CacheManager.create(); Cache myCache = new Cache("MyCache", 1, true, false, 0, 0); // Cache上设置为永不过期 manager.addCache(myCache); String key = "A"; System.out.println("-------------------------"); Element elementPut = new Element(key, "Some Value", 2, 0); // timeToIdleSeconds为2秒 myCache.put(elementPut);// 放入缓存 System.out.println(myCache.get(key));// 取出显示 Thread.sleep(1500);// 停1.5秒 System.out.println(myCache.get(key));// 再次取出 Thread.sleep(1500);// 停1.5秒 System.out.println(myCache.get(key));// 虽然总时间已达3秒,但刚刚被访问过了,所以又可以再"活"2秒,仍然有效 Thread.sleep(2500);// 停2.5秒 System.out.println(myCache.get(key));// 距离上次访问已过2.5s,已经>2s,过期 }
输出结果
[ key = A, value=Some Value, version=1, hitCount=1, CreationTime = 1407898361782, LastAccessTime = 1407898361787 ]
[ key = A, value=Some Value, version=1, hitCount=2, CreationTime = 1407898361782, LastAccessTime = 1407898363287 ]
[ key = A, value=Some Value, version=1, hitCount=3, CreationTime = 1407898361782, LastAccessTime = 1407898364787 ]
null
测试2:
@Test public void testTimeToLiveSeconds() throws InterruptedException { CacheManager manager = CacheManager.create(); Cache myCache = new Cache("MyCache", 1, true, false, 0, 0); // Cache上设置为永不过期 manager.addCache(myCache); String key = "A"; System.out.println("-------------------------"); Element elementPut = new Element(key, "Some Value", 0, 2); // timeToLiveSeconds为2秒 myCache.put(elementPut);// 放入缓存 System.out.println(myCache.get(key));// 取出显示 Thread.sleep(1500);// 停1.5秒 System.out.println(myCache.get(key));// 再次取出(1.5s<2s,还"活"着) Thread.sleep(1500);// 停1.5秒 System.out.println(myCache.get(key));// 总时间已达3s,>2s,已过期) }
输出结果
[ key = A, value=Some Value, version=1, hitCount=1, CreationTime = 1407898423291, LastAccessTime = 1407898423296 ]
[ key = A, value=Some Value, version=1, hitCount=2, CreationTime = 1407898423291, LastAccessTime = 1407898424797 ]
null
测试3:
@Test public void testTimeToIdleSecondsAndTimeToLiveSeconds() throws InterruptedException { CacheManager manager = CacheManager.create(); Cache myCache = new Cache("MyCache", 1, true, false, 0, 0); // Cache上设置为永不过期 manager.addCache(myCache); String key = "A"; System.out.println("-------------------------"); Element elementPut = new Element(key, "Some Value", 2, 5); // timeToIdleSeconds为2秒,timeToLiveSeconds为3秒 myCache.put(elementPut);// 放入缓存 System.out.println(myCache.get(key));// 取出显示 Thread.sleep(1600);// 停1.6秒 System.out.println(myCache.get(key));// 再次取出(1.6s < min(2 ,5),还"活"着) Thread.sleep(1600);// 停1.6秒 System.out.println(myCache.get(key));// 总时间已达3.2s,< min((1.6+2) ,5),还"活"着) Thread.sleep(1600);// 停1.6秒 System.out.println(myCache.get(key));// 总时间已达4.8s,< min((3.2+2) ,5),还"活"着) Thread.sleep(500);// 停0.5秒 System.out.println(myCache.get(key));// 总时间已达4.8+0.5=5.3s,> min((4.8+2) ,5),过期) }
输出结果
[ key = A, value=Some Value, version=1, hitCount=1, CreationTime = 1407898480892, LastAccessTime = 1407898480897 ]
[ key = A, value=Some Value, version=1, hitCount=2, CreationTime = 1407898480892, LastAccessTime = 1407898482499 ]
[ key = A, value=Some Value, version=1, hitCount=3, CreationTime = 1407898480892, LastAccessTime = 1407898484099 ]
[ key = A, value=Some Value, version=1, hitCount=4, CreationTime = 1407898480892, LastAccessTime = 1407898485699 ]
null
关于这二个参数的设置,个人建议是:
a) 如果缓存的数据本身不存在更新(比如:一些几乎从来不动的基础数据),只设置timeToIdleSeconds,这样的好处是,如果缓存项一直有人在访问,就永远不会过期,反之,如果没人用,空闲一段时间后,会自动过期,释放资源
b) 如果缓存的数据本身存在定期的更新问题(比如:天气预报之类每隔几小时,db中会更新的数据),可同时设置二个参数,timeToLiveSeconds的值应该要小于db中的更新周期,这样db中的数据变化后,过一段时间就会更新到缓存中
四、在spring中集成ehcache
1、需要添加的依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>3.0.5.RELEASE</version> </dependency>
2、在spring中的配置
<bean id="ehcacheCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation"> <value>classpath:ehcache.xml</value> </property> </bean>
相关推荐
ehcache 2.8.3 API EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。Ehcache是一种广泛使用的开 源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它...
ehcache-2.8.3 Java缓存框架
spring+ehcache示例整合Demo
NULL 博文链接:https://rmn190.iteye.com/blog/367903
NULL 博文链接:https://rmn190.iteye.com/blog/553761
spring+ehcache示例demo
开源测试项目:spring mvc+springsecurity3+ehcache+bootstrap+mysql 内附MySQL表,直接导入就可运行 效果图请移步:http://blog.csdn.net/yangxuan0261/article/details/10053947
赠送jar包:ehcache-3.9.9.jar; 赠送原API文档:ehcache-3.9.9-javadoc.jar; 赠送源代码:ehcache-3.9...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。 双语对照,边学技术、边学英语。
spring3整合EhCache注解实例
Spring与ehcache结合使用,本地缓存的实现
在Spring+Hibernate集成环境中使用EhCache缓存做的开发测试,在线程中打开数据库查询数据,及关闭数据库后查询数据的结果.
ehcache3-samples, 关于使用 Ehcache 3,一些示例/教程 Ehcache示例这里知识库包含有关 Ehcache 3用法的...示例'basic'演示 Ehcache 3的基本配置和用法'集群'- 演示如何在Terracotta服务器上使用分布式缓存功能'jsr107'
spring整合ehcache的入门级别demo分享,通过junit来测试
基于公司的项目在Spring中集成Ehcache,并提供EhcaheUtils工具类,并通过Spring的AOP编程实现方法缓存注解话,先奉献出核心代码,需要的朋友可以参考哦!
Hibernate的常用缓存jar包,可以和spring,Hibernate等框架进行整合。
1)Demo 学习要点简介: ...2.Eclipse 导入后可能需要在 Xml Catalog 手动添加:ehcache-spring-1.2.xsd(ehcache-spring-annotations-1.2.0-sources.jar里面有,自己找下)。 3.内附Oracle建表等可执行语句。
同时使用了Struts2、Spring4、Hibernate4、log4j、slf4j、junit4、ehcache等库或框架,搭建一个最基本的项目原型。 三、 三大框架最新版本下载:截止2014-10-01 Struts2.3.6:发布于2014-05-03,目前的最新版本。...
Ehcache 整合Spring 使用页面、对象缓存
在web.xml中配置spring容器的监听器。 2:项目集成springmvc 在web.xml中配置前端控制器 3:项目集成shiro 在web.xml中配置shiro过滤器 4:项目post乱码处理 在web.xml中配置字符过滤器 5:项目运行...
主要讲解下encache的原理、分布式缓存集群环境配置、与在spring中的使用