1.缓存接口
1.那么首先要提到的是缓存模块的缓存接口,该接口定义常用的缓存方法
package org.apache.ibatis.cache;
import java.util.concurrent.locks.ReadWriteLock;
public interface Cache {
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
int getSize();
ReadWriteLock getReadWriteLock();
}
2.默认的缓存实现类
2.其次再提到的是mybatis的默认缓存实现类,再impl包里面的PerpetualCache类
把实际需要缓存的数据存起来的办法有很多,那么mybatis给我提供的是用HashMap来存储数据。
package org.apache.ibatis.cache.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;
public class PerpetualCache implements Cache {
private final String id;
//实际存储交给HashMap去做了
private Map<Object, Object> cache = new HashMap<>();
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();
}
}
3.如何包装缓存失效算法
3.缓存就意味着有不同的失效算法,那么如何在缓存实现类中插入缓存失效算法呐,我们能够想到的是代理机制,就是创建代理类,然后再在代理方法里面插入需要的算法,
我们先讲讲动态代理机制:
1.构建一个包含代理处理方法的代理处理对象
2.就是使用代理接口类,创建代理对象
3.然后再把实际对象送入代理对象中
这几步虽然作为代理来说,适用范围广,但是写起来较为复杂,不方便高效率的阅读代码,作为只针对缓存接口的代理,就得用另一种方法了,mybatis当中的decorators(修饰)包就对就对缓存实现类用委托的方式来进行代理修饰,就是添加算法,那么我们再来与动态代理对象的比较。
他们的相同点是:1.都是继承接口类 2.都有把实际对象送入代理对象当中
那么用代码的方式看看他么的实现思路
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);
}
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;
}
};
}
@Override
public void putObject(Object key, Object value) {
delegate.putObject(key, value);
cycleKeyList(key);//往link集合li面放东西检查是否超限
}
private void cycleKeyList(Object key) {
keyMap.put(key, key);
if (eldestKey != null) {
delegate.removeObject(eldestKey);//如果超限,就移除旧的代码
eldestKey = null;
}
}
}
那么这里选取的部分代码可以看出,这个代理对象的实际执行原理是用LinkedHashMap的长度限制来缓存指定长度的数据,然后如果超限就移除旧有数据,怎么移除呐?通过委托传入的实际缓存对象来执行,就相当于给缓存对象包装上了一个缓存算法的衣服,当然也还可以包装多个缓存代理对象(姑且这么叫,其实叫修饰对象也可以),形成一个算法链。