所谓缓存清除策略,即当缓存空间已满,但又有新的元素要添加到缓存中时,选择清除哪些旧的缓存数据的策略。
ehcache支持3种缓存清除策略,如下所示:
FIFO —— 先进先出
当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有element中,最先被put到cache中的那些element被remove掉。
LFU —— Least Frequently Used,最少使用频率。
基于计数的算法。每个element被put到cache时,都会有一个hitCount成员变量用于计数,初始值为0。每次从cache中get一个element时,该element的hitCount值加1。
当缓存容量满了,而又需要腾出地方来缓存新的元素时,现有element中,hitCount最小的元素将被remove掉。
LRU —— Least Recently Used, 最近最少使用。
ehcache默认的缓存清除策略。每个element有一个lastAccessTime,当一个element被put到cache时,lastAccessTime被赋为当前时间值。随后每次从cache中get出该element时,lastAccessTime又会被更新为当前时间值。
当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有element中,lastAccessTime最小的一些元素将被remove掉。
PS:上述3种内置算法都是针对内存缓存(Memory Store),而不针对磁盘缓存(Disk Store)。磁盘缓存只使用LFU算法。
The disk store uses the Least Frequently Used algorithm to evict an element when the store it is full.
缓存清除策略在ehcache中称为policy,其API接口为Policy,定义如下:
public interface Policy {
//策略的名称
String getName();
//在候选Element中选出一个最应该被移除的element
Element selectedBasedOnPolicy(Element[] sampledElements, Element justAdded);
//比较两个element,哪一个更应该被移除
//返回值为true,表示第2个element优先被移除
//返回值为false,表示第1个element优先被移除
boolean compare(Element element1, Element element2);
}
内置策略所对应的类为FifoPolicy, LfuPolicy, LruPolicy。这3个类都不是直接实现Policy,而是继承于AbstractPolicy。
AbstractPolicy是一个抽象类,实现了Policy接口,使用了模板方法设计模式,仅实现selectedBaseOnPolicy()方法。该方法细节如下:
public Element selectedBasedOnPolicy(Element[] sampledElements, Element justAdded) {
//edge condition when Memory Store configured to size 0
if (sampledElements.length == 1)
return sampledElements[0];
Element lowestElement = null;
for (Element element : sampledElements)
{
if (element == null)
continue;
if (lowestElement == null)
{
if (!element.equals(justAdded))
lowestElement = element;
}
else if(compare(lowestElement, element) && !element.equals(justAdded))
lowestElement = element;
}
return lowestElement;
}
也就是说,不断调用compare()方法,以选出最应被清除的元素,同时注意把刚加进缓存的元素justAdded排除在外。
那么,分别看一下,FifoPolicy, LfuPolicy, LruPolicy的compare()方法。
public boolean compare(Element element1, Element element2) {
return element2.getLatestOfCreationAndUpdateTime() < element1.getLatestOfCreationAndUpdateTime();
}
public final long getLatestOfCreationAndUpdateTime() {
if (0 == lastUpdateTime) {
return creationTime;
} else {
return lastUpdateTime;
}
}
FIFO策略,比较element的创建先后顺序(中途被update,视为重新创建)。
public boolean compare(Element element1, Element element2) {
return element2.getHitCount() < element1.getHitCount();
}
LFU策略,比较hitCount计数的大小。
public boolean compare(Element element1, Element element2) {
return element2.getLastAccessTime() < element1.getLastAccessTime();
}
LRU策略,比较最后一次get的时间戳。
除了内置的三种缓存清除策略,ehcache还支持自定义缓存清除策略。从上述解析可看出,自定义策略,其实就是自定义子类,继承AbstractPolicy,并覆写getName和compare两个方法。示例:根据key的长短来清除element。
public class MyPolicy extends AbstractPolicy {
private static final String NAME = "MY_POLICY";
public String getName()
{
return NAME;
}
public boolean compare(Element element1, Element element2)
{
String key1 = (String) element1.getObjectKey();
String key2 = (String) element2.getObjectKey();
if(key1.compareToIgnoreCase(key2) < 0)
return false;
return true;
}
}
设置使用哪一种策略,有两种方式:
声明式
在ehcache.xml的<defaultCache>或<cache>标签中,设置memoryStoreEvictionPolicy属性,其值可为FIFO, LRU, LFU。
这种方式仅能用于设置内置的三种策略之一。
编程式
在Java Code中调用Cache的setMemoryStoreEvictionPolicy(Policy policy)方法。
这种方式可设置自定义的策略,当然也可设置内置的三种策略之一。
CacheManager cacheManager = CacheManager.newInstance();
Cache cache = cacheManager.getCache("getPerson");
cache.setMemoryStoreEvictionPolicy(new MyPolicy());