### 概述
Mybatis 缓存Cache是自己实现的,采用了简单+扩展性极强的装饰者模式实现,下图为缓存Cache实现体系
Cache实现
缓存Cache统一接口,由于实现是基于Map实现的,提供的方法名称基本上与Map接口一致
public interface Cache {
/**
* @return 标识
*/
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
int getSize();
/**
* 暂未使用
*/
ReadWriteLock getReadWriteLock();
}
PerpetualCache
PerpetualCache 缓存实现,基于HashMap
public class PerpetualCache implements Cache {
private final String id;
private Map<Object, Object> cache = new HashMap<Object, Object>();
public PerpetualCache(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public int getSize() {
return cache.size();
}
@Override
public void putObject(Object key, Object value) {
cache.put(key, value);
}
@Override
public Object getObject(Object key) {
return cache.get(key);
}
@Override
public Object removeObject(Object key) {
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
@Override
public boolean equals(Object o) {
if (getId() == null) {
throw new CacheException("Cache instances require an ID.");
}
if (this == o) {
return true;
}
if (!(o instanceof Cache)) {
return false;
}
Cache otherCache = (Cache) o;
return getId().equals(otherCache.getId());
}
@Override
public int hashCode() {
if (getId() == null) {
throw new CacheException("Cache instances require an ID.");
}
return getId().hashCode();
}
}
测试
public class PerpetualCacheTest_Copy {
@Test
public void shouldDemonstrateHowAllObjectsAreKept() {
Cache cache = new PerpetualCache("default");
for (int i = 0; i < 100000; i++) {
cache.putObject(i, i);
assertEquals(i, cache.getObject(i));
}
assertEquals(100000, cache.getSize());
}
@Test
public void shouldRemoveItemOnDemand() {
Cache cache = new PerpetualCache("default");
cache.putObject(0, 0);
assertNotNull(cache.getObject(0));
cache.removeObject(0);
assertNull(cache.getObject(0));
}
@Test
public void shouldFlushAllItemsOnDemand() {
Cache cache = new PerpetualCache("default");
for (int i = 0; i < 5; i++) {
cache.putObject(i, i);
}
assertNotNull(cache.getObject(0));
assertNotNull(cache.getObject(4));
cache.clear();
assertNull(cache.getObject(0));
assertNull(cache.getObject(4));
}
}
最基础的缓存功能,基于HashMap实现,为什么要定义属性String id
,通过一个测试类明白Mybatis设计
public class PerpetualCacheTest_Copy2 {
public static class MybatisConfiguration {
protected final Map<String, Cache> caches = new HashMap<>();
public void addCache(Cache cache) {
caches.put(cache.getId(), cache);
}
public Collection<String> getCacheNames() {
return caches.keySet();
}
public Collection<Cache> getCaches() {
return caches.values();
}
public Cache getCache(String id) {
return caches.get(id);
}
public boolean hasCache(String id) {
return caches.containsKey(id);
}
}
@Test
public void mybatisCacheImpl() {
MybatisConfiguration configuration = new MybatisConfiguration();
Cache shopCache = new PerpetualCache("shop");
for (int i = 0; i < 5; i++) {
shopCache.putObject(i, i);
}
configuration.addCache(shopCache);
Cache productCache = new PerpetualCache("product");
for (int i = 10; i < 25; i++) {
productCache.putObject(i, i);
}
configuration.addCache(productCache);
assertTrue(configuration.hasCache("shop"));
assertFalse(configuration.hasCache("store"));
Cache cache = configuration.getCache("shop");
assertEquals(0, cache.getObject(0));
assertEquals(5, cache.getSize());
}
}
我们可以看出id是为了区分不同的缓存,等于是一个分层处理
FifoCache
先进先出缓存Cache,设置缓存大小SITE,当缓存容量达到最大值SITE,需就先将remove缓存中的数据,再 put新数据。这里是基于Java中提供的双向队列Deque
容器来实现,需要依赖于其addLast
和removeFirst
方法
public class FifoCache implements Cache {
private final Cache delegate;
private final Deque<Object> keyList;
private int size;
public FifoCache(Cache delegate) {
this.delegate = delegate;
this.keyList = new LinkedList<Object>();
this.size = 1024;
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public int getSize() {
return delegate.getSize();
}
public void setSize(int size) {
this.size = size;
}
@Override
public void putObject(Object key, Object value) {
cycleKeyList(key);
delegate.putObject(key, value);
}
@Override
public Object getObject(Object key) {
return delegate.getObject(key);
}
@Override
public Object removeObject(Object key) {
return delegate.removeObject(key);
}
@Override
public void clear() {
delegate.clear();
keyList.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
private void cycleKeyList(Object key) {
keyList.addLast(key);
if (keyList.size() > size) {
Object oldestKey = keyList.removeFirst();
delegate.removeObject(oldestKey);
}
}
}
测试
public class FifoCacheTest {
@Test
public void shouldRemoveFirstItemInBeyondFiveEntries() {
FifoCache cache = new FifoCache(new PerpetualCache("default"));
cache.setSize(5);
for (int i = 0; i < 5; i++) {
cache.putObject(i, i);
}
assertNull(cache.getObject(5));
cache.putObject(5, 5);
assertNull(cache.getObject(0));
assertEquals(5, cache.getSize());
assertEquals(5, cache.getObject(5));
}
@Test
public void shouldRemoveItemOnDemand() {
FifoCache cache = new FifoCache(new PerpetualCache("default"));
cache.putObject(0, 0);
assertNotNull(cache.getObject(0));
cache.removeObject(0);
assertNull(cache.getObject(0));
}
@Test
public void shouldFlushAllItemsOnDemand() {
FifoCache cache = new FifoCache(new PerpetualCache("default"));
for (int i = 0; i < 5; i++) {
cache.putObject(i, i);
}
assertNotNull(cache.getObject(0));
assertNotNull(cache.getObject(4));
cache.clear();
assertNull(cache.getObject(0));
assertNull(cache.getObject(4));
}
}
LruCache
LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
基于LinkedHashMap实现
public class LruCache implements Cache {
private final Cache delegate;
private Map<Object, Object> keyMap;
private Object eldestKey;
public LruCache(Cache delegate) {
this.delegate = delegate;
setSize(1024);
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public int getSize() {
return delegate.getSize();
}
public void setSize(final int size) {
keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
private static final long serialVersionUID = 4267176411845948333L;
@Override
protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
boolean tooBig = size() > size;
if (tooBig) {
eldestKey = eldest.getKey();
}
return tooBig;
}
};
}
SoftCache
基于java 软连接实现缓存
public class SoftCache implements Cache {
private final Deque<Object> hardLinksToAvoidGarbageCollection;
private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;
private final Cache delegate;
private int numberOfHardLinks;
public SoftCache(Cache delegate) {
this.delegate = delegate;
this.numberOfHardLinks = 256;
this.hardLinksToAvoidGarbageCollection = new LinkedList<Object>();
this.queueOfGarbageCollectedEntries = new ReferenceQueue<Object>();
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public int getSize() {
removeGarbageCollectedItems();
return delegate.getSize();
}
public void setSize(int size) {
this.numberOfHardLinks = size;
}
@Override
public void putObject(Object key, Object value) {
removeGarbageCollectedItems();
delegate.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries));
}
@Override
public Object getObject(Object key) {
Object result = null;
@SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache
SoftReference<Object> softReference = (SoftReference<Object>) delegate.getObject(key);
if (softReference != null) {
result = softReference.get();
if (result == null) {
delegate.removeObject(key);
} else {
// See #586 (and #335) modifications need more than a read lock
synchronized (hardLinksToAvoidGarbageCollection) {
hardLinksToAvoidGarbageCollection.addFirst(result);
if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
hardLinksToAvoidGarbageCollection.removeLast();
}
}
}
}
return result;
}
@Override
public Object removeObject(Object key) {
removeGarbageCollectedItems();
return delegate.removeObject(key);
}
@Override
public void clear() {
synchronized (hardLinksToAvoidGarbageCollection) {
hardLinksToAvoidGarbageCollection.clear();
}
removeGarbageCollectedItems();
delegate.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
private void removeGarbageCollectedItems() {
SoftEntry sv;
while ((sv = (SoftEntry) queueOfGarbageCollectedEntries.poll()) != null) {
delegate.removeObject(sv.key);
}
}
private static class SoftEntry extends SoftReference<Object> {
private final Object key;
SoftEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) {
super(value, garbageCollectionQueue);
this.key = key;
}
}
}
其他的就不分析了,有兴趣的自己看看