第一章:Mybatis Orm的缓存
Mybatis定义了一个对象缓存,是Mybatis对缓存的封装,为了屏蔽实现的差异,这被定义成了一个接口Interface,这样的话,Mybatis的缓存基本上是存储于JVM内存中的。
一:Cache源码
public interface Cache {
String getId(); //每一个MapStatement都会有一个Cache,需要有一个编号。
void putObject(Object key, Object value); // 向缓存中添加
Object getObject(Object key); // 从缓存中获取数据
Object removeObject(Object key);//从缓存中删除数据
void clear();//清空
int getSize();//容量
ReadWriteLock getReadWriteLock();//读写锁是解决并发解决的。
}
Cache整个的存储结构,很类似于Java中Map。他使用的是JVM的内存。类似于键值对的这种结构。
第二章:自写Cache实现类
一:Map做容器
实现方式1:存多个数据,并且存键值对的数据。基本上容器就是Map了。
public class MyMybatisCache implements Cache {
private Map<Object,Object> internalCache = new HashMap();
@Override
public String getId() {
return getClass().getName() ;
}
@Override
public void putObject(Object key, Object value) {
internalCache.put(key,value);
}
@Override
public Object getObject(Object key) {
return internalCache.get(key);
}
@Override
public Object removeObject(Object key) {
return internalCache.remove(key);
}
@Override
public void clear() {
internalCache.clear();
}
@Override
public int getSize() {
return internalCache.size();
}
@Override
public ReadWriteLock getReadWriteLock() {
return new ReentrantReadWriteLock();
}
}
二:Jedis做容器
实现方式2:存多个数据,并且存键值对的数据。这里使用Redis也是可以的。
public class MyMybatisCache2 implements Cache {
@Override
public String getId() {
return null;
}
@Override
public void putObject(Object key, Object value) {
// redis java client ---> jedis
//Jedis jedis = JedisUtils.openJedis();
//key ---> json value--->json
//jedis.set(String,String);
//key --- byte[] value --- byte[]
//jedis.set(byte[],byte[]);
byte[] k = SerializationUtils.serialize((Serializable) key);
byte[] v = SerializationUtils.serialize((Serializable) value);
//jedis.set(k, v);
}
@Override
public Object getObject(Object key) {
if (key != null) {
byte[] k = SerializationUtils.serialize((Serializable) key);
//Jedis jedis = JedisUtils.openJedis();
// byte[] bytes = jedis.get(k);
// if(bytes !=null){
// Object value = SerializationUtils.deserialize(bytes);
// return value;
// }
}
return null;
}
@Override
public Object removeObject(Object key) {
return null;
}
@Override
public void clear() {
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
}
org.apache.commons下的commons-lang3这个包是阿帕奇对于Java.lang包下的功能的增强(String、toString、equals、hashCode、Serializable…)
第三章:Mybatis的Cache实现类
以下是Mybatis的Cache实现类的截图:
Mybatis对于Cache的实现类大致位于两个包:org.apache.ibatis.cache.decorators,org.apache.ibatis.cache.impl
核心的Cache实现位于Impl包下:PerpetualCache,剩下的都是基于装饰器模式,(装饰器的核心目的是为了他的目标增加功能)所以这些装饰器都不是核心,这里的核心就是PerpetualCache。
一:核心PerpetualCache
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();
}
}
底层使用HashMap来完成的,这个已经可以完成一个Cache基本的存储功能了。再次基础上想让Cache功能更强大,我们才用了装饰器的这样的Cache。
二:装饰器Cache
核心目标:为了让PerpetualCache的功能更加强大。
1:FifoCache和LruCache
增强了换出功能,换出功能最为核心的两种算法就是:Fifo先入先出,Lru最小使用。
Lru是默认的装饰器。
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 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;
}
};
}
@Override
public void putObject(Object key, Object value) {
delegate.putObject(key, value);
cycleKeyList(key);
}
@Override
public Object getObject(Object key) {
keyMap.get(key); //touch
return delegate.getObject(key);
}
@Override
public Object removeObject(Object key) {
return delegate.removeObject(key);
}
@Override
public void clear() {
delegate.clear();
keyMap.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
private void cycleKeyList(Object key) {
keyMap.put(key, key);
if (eldestKey != null) {
delegate.removeObject(eldestKey);
eldestKey = null;
}
}
}
如何体现装饰器设计模式的:
@Test
public void test2() {
//原始核心Cache只有基本功能
PerpetualCache perpetualCache = new PerpetualCache("sunshuai");
//套一层之后,引入了换出功能
LruCache lruCache = new LruCache(perpetualCache);
//再次套一层之后,引入了日志功能。
LoggingCache loggingCache = new LoggingCache(lruCache);
}
本质上就是一个套娃的过程,所有的装饰器和他的目标继承都是这个吊样。
2:LoggingCache
简单说明:增加日志打印功能
3:BlockingCache
简单说明:增加同一时间只会有一个线程去缓存中找某个key的值。
4:ScheduleCache
简单说明:定期刷新缓存,一段时间之后就自动清空缓存,这里边可以设置一个时间间隔,大于时间间隔之后就直接清空缓存。尽量解决脏数据的问题。
5:SerializableCache
简单说明:自动完成key,value的序列化和反序列化的过程。
6:TransactionalCache
简单说明:加上这个装饰器之后,只有在事务操作成功时,才会对应数据放到缓存中。
7:SoftCache和WeakCache
简单说明:这两个基本上就是纯概念性的东西,根部用不到
弱引用:xxxxxx
软引用:Tomcat在设计HttpSession的时候使用的是软引用。
设计模式的区分:装饰器模式和代理设计模式:
装饰器设计模式:
Mybatis当中大量增加了装饰器设计模式,目标是为了核心目标拓展功能,使用套娃的方式,一层一层的增加拓展工功能。
代理设计模式:
为目标原始目标增加额外功能。
如何去区分和权衡呢?
装饰器和代理设计模式,他们的原始功能是不一样的,装饰器设计模式拓展的功能是他的本职工作,比方说Mybatis当中的装饰器模式,增强的是就是他的本质核心原始功能;而代理设计模式增加的是额外功能,跟他们本质原始功能是有根本区别的,比如说是对于Service增加了事务的功能,事务和我们原始Service的功能是不一致的,这是二者最本质的区别。
装饰器设计模式能套娃,代理设计模式不行,这样的描述对么?
一般代理很少套娃,但是不代表他不能套娃。代理也是可以套娃的,JDK的动态代理就可以实现。这里可以补充一下代码。
代理能做到无中生有
当你给我一个接口的时候,我只能通过动态代理这种方式帮你自动的创建接口的实现类,这件事装饰器做不了。最典型的就是SqlSesission中的getMapper();
GOF4人帮只提供了23中设计模式,除了这几种之后,还有委托设计模式…他们不属于23中经典的范畴。这些个设计模式他有这种开发中有这些特点:
1:Java开发中用不全23中设计模式。有些设计模式不适用于微服务和web开发
2:23中设计模式有很多很类似的东西,很像,这样的话,我们就需要区分,比如说我们的代理和装饰器。甚至,我们很多时候会把代理和装饰器和适配器做区分。
3:Mybatis当中还有工厂、建造者等等设计模式。