一、pom.xml 依赖项
1 <dependency>
2 <groupId>net.sf.ehcache</groupId>
3 <artifactId>ehcache</artifactId>
4 <version>2.8.3</version>
5 </dependency>
6
7 <dependency>
8 <groupId>org.slf4j</groupId>
9 <artifactId>slf4j-api</artifactId>
10 <version>1.7.7</version>
11 </dependency>
二、ehcache.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
5 monitoring="autodetect" dynamicConfig="true">
6
7
8 <diskStore path="java.io.tmpdir" />
9
10 <defaultCache maxEntriesLocalHeap="10000" eternal="false"
11 timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"
12 maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"
13 memoryStoreEvictionPolicy="LRU">
14 <persistence strategy="localTempSwap" />
15 </defaultCache>
16
17 <cache name="sampleCache1" maxEntriesLocalHeap="10000"
18 maxEntriesLocalDisk="1000" eternal="false" diskSpoolBufferSizeMB="20"
19 timeToIdleSeconds="300" timeToLiveSeconds="600"
20 memoryStoreEvictionPolicy="LFU" transactionalMode="off">
21 <persistence strategy="localTempSwap" />
22 </cache>
23
24 <cache name="sampleCache2" maxEntriesLocalHeap="1000" eternal="true"
25 memoryStoreEvictionPolicy="FIFO" />
26
27 </ehcache>
三、示例代码
1 package cnblogs.ehcache;
2
3 import net.sf.ehcache.Cache;
4 import net.sf.ehcache.CacheManager;
5 import net.sf.ehcache.Element;
6
7 public class App {
8 public static void main(String[] args) throws InterruptedException {
9 CacheManager manager = CacheManager.create();
10
11 // 取出所有的cacheName
12 String names[] = manager.getCacheNames();
13 System.out.println("----all cache names----");
14 for (int i = 0; i < names.length; i++) {
15 System.out.println(names[i]);
16 }
17
18 System.out.println("----------------------");
19 // 得到一个cache对象
20 Cache cache1 = manager.getCache(names[0]);
21
22 // 向cache1对象里添加缓存
23 cache1.put(new Element("key1", "values1"));
24 Element element = cache1.get("key1");
25
26 // 读取缓存
27 System.out.println("key1 \t= " + element.getObjectValue());
28
29 // 手动创建一个cache(ehcache里必须有defaultCache存在,"test"可以换成任何值)
30 Cache cache2 = new Cache("test", 1, true, false, 2, 3);
31 manager.addCache(cache2);
32
33 cache2.put(new Element("jimmy", "菩提树下的杨过"));
34
35 // 故意停1.5秒,以验证是否过期
36 Thread.sleep(1500);
37
38 Element eleJimmy = cache2.get("jimmy");
39
40 //1.5s < 2s 不会过期
41 if (eleJimmy != null) {
42 System.out.println("jimmy \t= " + eleJimmy.getObjectValue());
43 }
44
45 //再等上0.5s, 总时长:1.5 + 0.5 >= min(2,3),过期
46 Thread.sleep(500);
47
48 eleJimmy = cache2.get("jimmy");
49
50 if (eleJimmy != null) {
51 System.out.println("jimmy \t= " + eleJimmy.getObjectValue());
52 }
53
54 // 取出一个不存在的缓存项
55 System.out.println("fake \t= " + cache2.get("fake"));
56
57 manager.shutdown();
58 }
59
60 }
运行结果:
----all cache names---- sampleCache2 sampleCache1 ---------------------- key1 = values1 jimmy = 菩提树下的杨过 fake = null
四、关于timeToLiveSeconds、timeToIdleSeconds
这二个参数直接影响缓存项的过期时间,看文档说明基本上没啥用,直接看net.sf.ehcache.Element源码的片段:
1 /**
2 * The amount of time for the element to live, in seconds. 0 indicates unlimited.
3 */
4 private volatile int timeToLive = Integer.MIN_VALUE;
5
6 /**
7 * The amount of time for the element to idle, in seconds. 0 indicates unlimited.
8 */
9 private volatile int timeToIdle = Integer.MIN_VALUE;
10
11
12 /**
13 * Sets time to Live
14 * <P/>
15 * Value must be a positive integer, 0 means infinite time to live.
16 * <P/>
17 * If calling this method with 0 as the parameter, consider using {@link #setEternal(boolean)}
18 * or make sure you also explicitly call {@link #setTimeToIdle(int)}.
19 *
20 * @param timeToLiveSeconds the number of seconds to live
21 */
22 public void setTimeToLive(final int timeToLiveSeconds) {
23 if (timeToLiveSeconds < 0) {
24 throw new IllegalArgumentException("timeToLive can't be negative");
25 }
26 this.cacheDefaultLifespan = false;
27 this.timeToLive = timeToLiveSeconds;
28 }
29
30 /**
31 * Sets time to idle
32 * <P/>
33 * Value must be a positive integer, 0 means infinite time to idle.
34 * <P/>
35 * If calling this method with 0 as the parameter, consider using {@link #setEternal(boolean)}
36 * or make sure you also explicitly call {@link #setTimeToLive(int)}.
37 *
38 * @param timeToIdleSeconds the number of seconds to idle
39 */
40 public void setTimeToIdle(final int timeToIdleSeconds) {
41 if (timeToIdleSeconds < 0) {
42 throw new IllegalArgumentException("timeToIdle can't be negative");
43 }
44 this.cacheDefaultLifespan = false;
45 this.timeToIdle = timeToIdleSeconds;
46 }
47
48
49
50 /**
51 * An element is expired if the expiration time as given by {@link #getExpirationTime()} is in the past.
52 *
53 * @return true if the Element is expired, otherwise false. If no lifespan has been set for the Element it is
54 * considered not able to expire.
55 * @see #getExpirationTime()
56 */
57 public boolean isExpired() {
58 if (!isLifespanSet() || isEternal()) {
59 return false;
60 }
61
62 long now = System.currentTimeMillis();
63 long expirationTime = getExpirationTime();
64
65 return now > expirationTime;
66 }
67
68
69 /**
70 * An element is expired if the expiration time as given by {@link #getExpirationTime()} is in the past.
71 * <p>
72 * This method in addition propogates the default TTI/TTL values of the supplied cache into this element.
73 *
74 * @param config config to take default parameters from
75 * @return true if the Element is expired, otherwise false. If no lifespan has been set for the Element it is
76 * considered not able to expire.
77 * @see #getExpirationTime()
78 */
79 public boolean isExpired(CacheConfiguration config) {
80 if (cacheDefaultLifespan) {
81 if (config.isEternal()) {
82 timeToIdle = 0;
83 timeToLive = 0;
84 } else {
85 timeToIdle = TimeUtil.convertTimeToInt(config.getTimeToIdleSeconds());
86 timeToLive = TimeUtil.convertTimeToInt(config.getTimeToLiveSeconds());
87 }
88 }
89 return isExpired();
90 }
91
92 /**
93 * Returns the expiration time based on time to live. If this element also has a time to idle setting, the expiry
94 * time will vary depending on whether the element is accessed.
95 *
96 * @return the time to expiration
97 */
98 public long getExpirationTime() {
99 if (!isLifespanSet() || isEternal()) {
100 return Long.MAX_VALUE;
101 }
102
103 long expirationTime = 0;
104 long ttlExpiry = creationTime + TimeUtil.toMillis(getTimeToLive());
105
106 long mostRecentTime = Math.max(creationTime, lastAccessTime);
107 long ttiExpiry = mostRecentTime + TimeUtil.toMillis(getTimeToIdle());
108
109 if (getTimeToLive() != 0 && (getTimeToIdle() == 0 || lastAccessTime == 0)) {
110 expirationTime = ttlExpiry;
111 } else if (getTimeToLive() == 0) {
112 expirationTime = ttiExpiry;
113 } else {
114 expirationTime = Math.min(ttlExpiry, ttiExpiry);
115 }
116 return expirationTime;
117 }
118
119 /**
120 * @return true if the element is eternal
121 */
122 public boolean isEternal() {
123 return (0 == timeToIdle) && (0 == timeToLive);
124 }
125
126
127 /**
128 * Sets whether the element is eternal.
129 *
130 * @param eternal
131 */
132 public void setEternal(final boolean eternal) {
133 if (eternal) {
134 this.cacheDefaultLifespan = false;
135 this.timeToIdle = 0;
136 this.timeToLive = 0;
137 } else if (isEternal()) {
138 this.cacheDefaultLifespan = false;
139 this.timeToIdle = Integer.MIN_VALUE;
140 this.timeToLive = Integer.MIN_VALUE;
141 }
142 }
143
144 /**
145 * Whether any combination of eternal, TTL or TTI has been set.
146 *
147 * @return true if set.
148 */
149 public boolean isLifespanSet() {
150 return this.timeToIdle != Integer.MIN_VALUE || this.timeToLive != Integer.MIN_VALUE;
151 }
152
153 /**
154 * @return the time to live, in seconds
155 */
156 public int getTimeToLive() {
157 if (Integer.MIN_VALUE == timeToLive) {
158 return 0;
159 } else {
160 return timeToLive;
161 }
162 }
163
164 /**
165 * @return the time to idle, in seconds
166 */
167 public int getTimeToIdle() {
168 if (Integer.MIN_VALUE == timeToIdle) {
169 return 0;
170 } else {
171 return timeToIdle;
172 }
173 }
174
175
176 /**
177 * Set the default parameters of this element - those from its enclosing cache.
178 * @param tti TTI in seconds
179 * @param ttl TTL in seconds
180 * @param eternal <code>true</code> if the element is eternal.
181 */
182 protected void setLifespanDefaults(int tti, int ttl, boolean eternal) {
183 if (eternal) {
184 this.timeToIdle = 0;
185 this.timeToLive = 0;
186 } else if (isEternal()) {
187 this.timeToIdle = Integer.MIN_VALUE;
188 this.timeToLive = Integer.MIN_VALUE;
189 } else {
190 timeToIdle = tti;
191 timeToLive = ttl;
192 }
193 }
结论:
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:
1 @Test
2 public void testTimeToIdleSeconds() throws InterruptedException {
3 CacheManager manager = CacheManager.create();
4
5 Cache myCache = new Cache("MyCache", 1, true, false, 0, 0); // Cache上设置为永不过期
6 manager.addCache(myCache);
7
8 String key = "A";
9
10 System.out.println("-------------------------");
11 Element elementPut = new Element(key, "Some Value", 2, 0); // timeToIdleSeconds为2秒
12
13 myCache.put(elementPut);// 放入缓存
14 System.out.println(myCache.get(key));// 取出显示
15
16 Thread.sleep(1500);// 停1.5秒
17 System.out.println(myCache.get(key));// 再次取出
18
19 Thread.sleep(1500);// 停1.5秒
20 System.out.println(myCache.get(key));// 虽然总时间已达3秒,但刚刚被访问过了,所以又可以再"活"2秒,仍然有效
21
22 Thread.sleep(2500);// 停2.5秒
23 System.out.println(myCache.get(key));// 距离上次访问已过2.5s,已经>2s,过期
24
25 }
输出结果
[ 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:
1 @Test
2 public void testTimeToLiveSeconds() throws InterruptedException {
3 CacheManager manager = CacheManager.create();
4
5 Cache myCache = new Cache("MyCache", 1, true, false, 0, 0); // Cache上设置为永不过期
6 manager.addCache(myCache);
7
8 String key = "A";
9
10 System.out.println("-------------------------");
11 Element elementPut = new Element(key, "Some Value", 0, 2); // timeToLiveSeconds为2秒
12
13 myCache.put(elementPut);// 放入缓存
14 System.out.println(myCache.get(key));// 取出显示
15
16 Thread.sleep(1500);// 停1.5秒
17 System.out.println(myCache.get(key));// 再次取出(1.5s<2s,还"活"着)
18
19 Thread.sleep(1500);// 停1.5秒
20 System.out.println(myCache.get(key));// 总时间已达3s,>2s,已过期)
21
22 }
输出结果
[ 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:
1 @Test
2 public void testTimeToIdleSecondsAndTimeToLiveSeconds()
3 throws InterruptedException {
4 CacheManager manager = CacheManager.create();
5
6 Cache myCache = new Cache("MyCache", 1, true, false, 0, 0); // Cache上设置为永不过期
7 manager.addCache(myCache);
8
9 String key = "A";
10
11 System.out.println("-------------------------");
12 Element elementPut = new Element(key, "Some Value", 2, 5); // timeToIdleSeconds为2秒,timeToLiveSeconds为3秒
13
14 myCache.put(elementPut);// 放入缓存
15 System.out.println(myCache.get(key));// 取出显示
16
17 Thread.sleep(1600);// 停1.6秒
18 System.out.println(myCache.get(key));// 再次取出(1.6s < min(2 ,5),还"活"着)
19
20 Thread.sleep(1600);// 停1.6秒
21 System.out.println(myCache.get(key));// 总时间已达3.2s,< min((1.6+2) ,5),还"活"着)
22
23 Thread.sleep(1600);// 停1.6秒
24 System.out.println(myCache.get(key));// 总时间已达4.8s,< min((3.2+2) ,5),还"活"着)
25
26 Thread.sleep(500);// 停0.5秒
27 System.out.println(myCache.get(key));// 总时间已达4.8+0.5=5.3s,> min((4.8+2) ,5),过期)
28
29 }
输出结果
[ 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中的数据变化后,过一段时间就会更新到缓存中