第一章: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当中还有工厂、建造者等等设计模式。