一、类结构
二、AbstractEmbeddedCache
- 定义了InnerMap和创建InnerMap的抽象方法,由LinkedHashMapCache和CaffeineCache两个子类来实现。
protected InnerMap innerMap;
protected abstract InnerMap createAreaCache();
- 在这个类中实现了一些公共方法,避免子类重复实现,公共方法会调用如innerMap.getValue(newKey),使用每个子类的独立实现。
@Override
protected CacheGetResult<V> do_GET(K key) {
Object newKey = buildKey(key);
// 委托给innerMap,也可以是定义一个模板方法,由子类实现,但innerMap可将所有待实现模板方法内聚到一起,也更独立
CacheValueHolder<V> holder = (CacheValueHolder<V>) innerMap.getValue(newKey);
return parseHolderResult(holder);
}
parseHolderResult方法:
- 其中CacheGetResult类似于一个ResponseEntity类,封装了我们想要响应的数据。
- CacheValueHolder类似于一个Vo类,存了value,expireTime和accessTime的值。
- 这个方法的作用是先判断这个值是否过期;再加锁判断距离上次使用时间是否超过限制;未超出限制则设置新的accessTime;最后将数据封装在CacheGetResult中。
protected CacheGetResult<V> parseHolderResult(CacheValueHolder<V> holder) {
long now = System.currentTimeMillis();
if (holder == null) {
return CacheGetResult.NOT_EXISTS_WITHOUT_MSG;
} else if (now >= holder.getExpireTime()) {
return CacheGetResult.EXPIRED_WITHOUT_MSG;
} else {
synchronized (holder) {
long accessTime = holder.getAccessTime();
if (config.isExpireAfterAccess()) {
long expireAfterAccess = config.getExpireAfterAccessInMillis();
if (now >= accessTime + expireAfterAccess) {
return CacheGetResult.EXPIRED_WITHOUT_MSG;
}
}
holder.setAccessTime(now);
}
return new CacheGetResult(CacheResultCode.SUCCESS, null, holder);
}
}
InnerMap接口:
- 将需要子类实现的方法都内聚到一个类中,可扩展性更强。
public interface InnerMap {
Object getValue(Object key);
Map getAllValues(Collection keys);
void putValue(Object key, Object value);
void putAllValues(Map map);
boolean removeValue(Object key);
boolean putIfAbsentValue(Object key, Object value);
void removeAllValues(Collection keys);
}
三、LinkedHashMapCache
在其中定义了一个内部类LRUMap,继承了LinkedHashMap,并实现了InnerMap接口。
实际上LRUMap就是基于LinkedHashMap的数据结构,增加了一些控制缓存过期,和实现JSR107规范的一些方法。
package com.alicp.jetcache.embedded;
import com.alicp.jetcache.CacheResultCode;
import com.alicp.jetcache.CacheValueHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
*/
public class LinkedHashMapCache<K, V> extends AbstractEmbeddedCache<K, V> {
private static Logger logger = LoggerFactory.getLogger(LinkedHashMapCache.class);
public LinkedHashMapCache(EmbeddedCacheConfig<K, V> config) {
super(config);
addToCleaner();
}
protected void addToCleaner() {
Cleaner.add(this);
}
@Override
protected InnerMap createAreaCache() {
return new LRUMap(config.getLimit(), this);
}
@Override
public <T> T unwrap(Class<T> clazz) {
if (clazz.equals(LinkedHashMap.class)) {
return (T) innerMap;
}
throw new IllegalArgumentException(clazz.getName());
}
public void cleanExpiredEntry() {
((LRUMap) innerMap).cleanExpiredEntry();
}
// 内部类
final class LRUMap extends LinkedHashMap implements InnerMap {
private final int max;
private Object lock;
//accessOrder为true,是基于访问排序,accessOrder为false基于插入排序。我们想要LinkedHashMap实现LRU功能,accessOrder必须为true。如果accessOrder为false,那就是FIFO了。
public LRUMap(int max, Object lock) {
super((int) (max * 1.4f), 0.75f, true);
this.max = max;
this.lock = lock;
}
//重写removeEldestEntry方法,map容量大于最大值时触发淘汰策略
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > max;
}
// 清理失效缓存
void cleanExpiredEntry() {
synchronized (lock) {
for (Iterator it = entrySet().iterator(); it.hasNext();) {
Map.Entry en = (Map.Entry) it.next();
Object value = en.getValue();
if (value != null && value instanceof CacheValueHolder) {
CacheValueHolder h = (CacheValueHolder) value;
logger.info("CacheValueHolder: " + h.toString());
if (System.currentTimeMillis() >= h.getExpireTime()) {
it.remove();
}
} else {
// assert false
if (value == null) {
logger.error("key " + en.getKey() + " is null");
} else {
logger.error("value of key " + en.getKey() + " is not a CacheValueHolder. type=" + value.getClass());
}
}
}
}
}
@Override
public Object getValue(Object key) {
synchronized (lock) {
return get(key);
}
}
@Override
public Map getAllValues(Collection keys) {
Map values = new HashMap();
synchronized (lock) {
for (Object key : keys) {
Object v = get(key);
if (v != null) {
values.put(key, v);
}
}
}
return values;
}
@Override
public void putValue(Object key, Object value) {
synchronized (lock) {
put(key, value);
}
}
@Override
public void putAllValues(Map map) {
synchronized (lock) {
Set<Map.Entry> set = map.entrySet();
for (Map.Entry en : set) {
put(en.getKey(), en.getValue());
}
}
}
@Override
public boolean removeValue(Object key) {
synchronized (lock) {
return remove(key) != null;
}
}
@Override
public void removeAllValues(Collection keys) {
synchronized (lock) {
for (Object k : keys) {
remove(k);
}
}
}
@Override
@SuppressWarnings("unchecked")
public boolean putIfAbsentValue(Object key, Object value) {
synchronized (lock) {
CacheValueHolder h = (CacheValueHolder) get(key);
if (h == null || parseHolderResult(h).getResultCode() == CacheResultCode.EXPIRED) {
put(key, value);
return true;
} else {
return false;
}
}
}
}
}
LinkedHashMap三个控制插入、删除有序性的方法:
- afterNodeAccess方法
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
//当accessOrder的值为true,且e不是尾节点
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
这段代码的意思就是把当前节点e移至链表的尾部。因为使用的是双向链表,所以在尾部插入可以以O(1)的时间复杂度来完成。并且只有当accessOrder设置为true时,才会执行这个操作。在HashMap的putVal方法中,就调用了这个方法。
- afterNodeInsertion方法
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
afterNodeInsertion方法是在哈希表中插入了一个新节点时调用的,它会把链表的头节点删除掉,删除的方式是通过调用HashMap的removeNode方法。通过afterNodeInsertion方法和afterNodeAccess方法,可以实现一个简单的LRU了,removeEldestEntry这方法需要重写,定义何时会触发lru。
- afterNodeRemoval方法
void afterNodeRemoval(Node<K,V> e) { // unlink
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.before = p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
这个方法是当HashMap删除一个键值对时调用的,它会把在HashMap中删除的那个键值对一并从链表中删除,保证了哈希表和链表的一致性。
四、CaffeineCache
将所有的操作都委托给一个Caffeine类型的cache对象。
package com.alicp.jetcache.embedded;
import com.alicp.jetcache.CacheValueHolder;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Expiry;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Created on 2016/10/25.
*
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
*/
public class CaffeineCache<K, V> extends AbstractEmbeddedCache<K, V> {
// 持有caffeine的缓存实例,方法调用最终都委托给它
private com.github.benmanes.caffeine.cache.Cache cache;
public CaffeineCache(EmbeddedCacheConfig<K, V> config) {
super(config);
}
@Override
public <T> T unwrap(Class<T> clazz) {
if (clazz.equals(com.github.benmanes.caffeine.cache.Cache.class)) {
return (T) cache;
}
throw new IllegalArgumentException(clazz.getName());
}
@Override
@SuppressWarnings("unchecked")
protected InnerMap createAreaCache() {
// Builder设计模式
Caffeine<Object, Object> builder = Caffeine.newBuilder();
builder.maximumSize(config.getLimit());
final boolean isExpireAfterAccess = config.isExpireAfterAccess();
final long expireAfterAccess = config.getExpireAfterAccessInMillis();
// 通过依赖注入重载默认实现
builder.expireAfter(new Expiry<Object, CacheValueHolder>() {
private long getRestTimeInNanos(CacheValueHolder value) {
long now = System.currentTimeMillis();
long ttl = value.getExpireTime() - now;
if(isExpireAfterAccess){
ttl = Math.min(ttl, expireAfterAccess);
}
return TimeUnit.MILLISECONDS.toNanos(ttl);
}
@Override
public long expireAfterCreate(Object key, CacheValueHolder value, long currentTime) {
return getRestTimeInNanos(value);
}
@Override
public long expireAfterUpdate(Object key, CacheValueHolder value,
long currentTime, long currentDuration) {
return currentDuration;
}
@Override
public long expireAfterRead(Object key, CacheValueHolder value,
long currentTime, long currentDuration) {
return getRestTimeInNanos(value);
}
});
cache = builder.build();
// 因为调用关系比较简单,使用了匿名内部类
return new InnerMap() {
@Override
public Object getValue(Object key) {
return cache.getIfPresent(key);
}
@Override
public Map getAllValues(Collection keys) {
return cache.getAllPresent(keys);
}
@Override
public void putValue(Object key, Object value) {
cache.put(key, value);
}
@Override
public void putAllValues(Map map) {
cache.putAll(map);
}
@Override
public boolean removeValue(Object key) {
return cache.asMap().remove(key) != null;
}
@Override
public void removeAllValues(Collection keys) {
cache.invalidateAll(keys);
}
@Override
public boolean putIfAbsentValue(Object key, Object value) {
return cache.asMap().putIfAbsent(key, value) == null;
}
};
}
}