MyBatis源码之缓存模块 1. Cache
是一个容器,有点类似 HashMap ,可以往其中添加各种缓存
PerpetualCache 默认cache的实现类, 不用装饰, 其它缓存类均采用装饰者模式, 因为只是对Cache方法前后的扩展, 而不去更改Cache的方法
所在包: org.apache.ibatis.cache.Cache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 void putObject (Object key, Object value) ; Object getObject (Object key) ; Object removeObject (Object key) ; void clear () ; int getSize () ; default ReadWriteLock getReadWriteLock () { return null ; } }
1.1 PerpetualCache
实现 Cache 接口,永不过期 的 Cache 实现类,基于 HashMap 实现类, 所在包: org.apache.ibatis.cache.impl.PerpetualCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class PerpetualCache implements Cache { private final String id; private final 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(); } }
1.2 LoggingCache
实现 Cache 接口,支持打印日志 的 Cache 实现类, 所在包: org.apache.ibatis.cache.decorators.LoggingCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 public class LoggingCache implements Cache { private final Log log; private final Cache delegate; protected int requests; protected int hits; public LoggingCache (Cache delegate) { this .delegate = delegate; this .log = LogFactory.getLog(getId()); } @Override public String getId () { return delegate.getId(); } @Override public int getSize () { return delegate.getSize(); } @Override public void putObject (Object key, Object object) { delegate.putObject(key, object); } @Override public Object getObject (Object key) { requests++; final Object value = delegate.getObject(key); if (value != null ) { hits++; } if (log.isDebugEnabled()) { log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio()); } return value; } @Override public Object removeObject (Object key) { return delegate.removeObject(key); } @Override public void clear () { delegate.clear(); } @Override public int hashCode () { return delegate.hashCode(); } @Override public boolean equals (Object obj) { return delegate.equals(obj); } private double getHitRatio () { return (double ) hits / (double ) requests; } }
1.3 BlockingCache
实现 Cache 接口,阻塞的 Cache 实现类, 当A线程未获取到缓存数据时, 其它线程会阻塞, 因为A线程未获取到数据会获取对应的值并设置对应的缓存值, 防止其它线程重复设置缓存值
所在包: org.apache.ibatis.cache.decoratorsBlockingCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 public class BlockingCache implements Cache { private long timeout; private final Cache delegate; private final ConcurrentHashMap<Object, CountDownLatch> locks; public BlockingCache (Cache delegate) { this .delegate = delegate; this .locks = new ConcurrentHashMap <>(); } @Override public String getId () { return delegate.getId(); } @Override public int getSize () { return delegate.getSize(); } @Override public void putObject (Object key, Object value) { try { delegate.putObject(key, value); } finally { releaseLock(key); } } @Override public Object getObject (Object key) { acquireLock(key); Object value = delegate.getObject(key); if (value != null ) { releaseLock(key); } return value; } @Override public Object removeObject (Object key) { releaseLock(key); return null ; } @Override public void clear () { delegate.clear(); } private void acquireLock (Object key) { CountDownLatch newLatch = new CountDownLatch (1 ); while (true ) { CountDownLatch latch = locks.putIfAbsent(key, newLatch); if (latch == null ) { break ; } try { if (timeout > 0 ) { boolean acquired = latch.await(timeout, TimeUnit.MILLISECONDS); if (!acquired) { throw new CacheException ( "Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId()); } } else { latch.await(); } } catch (InterruptedException e) { throw new CacheException ("Got interrupted while trying to acquire lock for key " + key, e); } } } private void releaseLock (Object key) { CountDownLatch latch = locks.remove(key); if (latch == null ) { throw new IllegalStateException ("Detected an attempt at releasing unacquired lock. This should never happen." ); } latch.countDown(); } public long getTimeout () { return timeout; } public void setTimeout (long timeout) { this .timeout = timeout; } }
1.4 SynchronizedCache
实现 Cache 接口,同步 的 Cache 实现类, 所在包: org.apache.ibatis.cache.decorators.SynchronizedCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 public class SynchronizedCache implements Cache { private final ReentrantLock lock = new ReentrantLock (); private final Cache delegate; public SynchronizedCache (Cache delegate) { this .delegate = delegate; } @Override public String getId () { return delegate.getId(); } @Override public int getSize () { lock.lock(); try { return delegate.getSize(); } finally { lock.unlock(); } } @Override public void putObject (Object key, Object object) { lock.lock(); try { delegate.putObject(key, object); } finally { lock.unlock(); } } @Override public Object getObject (Object key) { lock.lock(); try { return delegate.getObject(key); } finally { lock.unlock(); } } @Override public Object removeObject (Object key) { lock.lock(); try { return delegate.removeObject(key); } finally { lock.unlock(); } } @Override public void clear () { lock.lock(); try { delegate.clear(); } finally { lock.unlock(); } } }
1.5 SerializedCache
实现 Cache 接口,支持序列化值 的 Cache 实现类, 所在包: org.apache.ibatis.cache.decorators.SerializedCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 public class SerializedCache implements Cache { private final Cache delegate; public SerializedCache (Cache delegate) { this .delegate = delegate; } @Override public String getId () { return delegate.getId(); } @Override public int getSize () { return delegate.getSize(); } @Override public void putObject (Object key, Object object) { if ((object != null ) && !(object instanceof Serializable)) { throw new CacheException ("SharedCache failed to make a copy of a non-serializable object: " + object); } delegate.putObject(key, serialize((Serializable) object)); } @Override public Object getObject (Object key) { Object object = delegate.getObject(key); return object == null ? null : deserialize((byte []) object); } @Override public Object removeObject (Object key) { return delegate.removeObject(key); } @Override public void clear () { delegate.clear(); } @Override public int hashCode () { return delegate.hashCode(); } @Override public boolean equals (Object obj) { return delegate.equals(obj); } private byte [] serialize(Serializable value) { try (ByteArrayOutputStream bos = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (bos)) { oos.writeObject(value); oos.flush(); return bos.toByteArray(); } catch (Exception e) { throw new CacheException ("Error serializing object. Cause: " + e, e); } } private Serializable deserialize (byte [] value) { SerialFilterChecker.check(); Serializable result; try (ByteArrayInputStream bis = new ByteArrayInputStream (value); ObjectInputStream ois = new CustomObjectInputStream (bis)) { result = (Serializable) ois.readObject(); } catch (Exception e) { throw new CacheException ("Error deserializing object. Cause: " + e, e); } return result; } public static class CustomObjectInputStream extends ObjectInputStream { public CustomObjectInputStream (InputStream in) throws IOException { super (in); } @Override protected Class<?> resolveClass(ObjectStreamClass desc) throws ClassNotFoundException { return Resources.classForName(desc.getName()); } } }
1.6 ScheduledCache
实现 Cache 接口,定时清空整个容器 的 Cache 实现类, 所在包: org.apache.ibatis.cache.decorators.ScheduledCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 public class ScheduledCache implements Cache { private final Cache delegate; protected long clearInterval; protected long lastClear; public ScheduledCache (Cache delegate) { this .delegate = delegate; this .clearInterval = TimeUnit.HOURS.toMillis(1 ); this .lastClear = System.currentTimeMillis(); } public void setClearInterval (long clearInterval) { this .clearInterval = clearInterval; } @Override public String getId () { return delegate.getId(); } @Override public int getSize () { clearWhenStale(); return delegate.getSize(); } @Override public void putObject (Object key, Object object) { clearWhenStale(); delegate.putObject(key, object); } @Override public Object getObject (Object key) { return clearWhenStale() ? null : delegate.getObject(key); } @Override public Object removeObject (Object key) { clearWhenStale(); return delegate.removeObject(key); } @Override public void clear () { lastClear = System.currentTimeMillis(); delegate.clear(); } @Override public int hashCode () { return delegate.hashCode(); } @Override public boolean equals (Object obj) { return delegate.equals(obj); } private boolean clearWhenStale () { if (System.currentTimeMillis() - lastClear > clearInterval) { clear(); return true ; } return false ; } }
1.7 FifoCache
实现 Cache 接口,基于先进先出的淘汰机制 的 Cache 实现类, 所在包: org.apache.ibatis.cache.decorators.FifoCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 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 <>(); 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) { keyList.remove(key); return delegate.removeObject(key); } @Override public void clear () { delegate.clear(); keyList.clear(); } private void cycleKeyList (Object key) { keyList.addLast(key); if (keyList.size() > size) { Object oldestKey = keyList.removeFirst(); delegate.removeObject(oldestKey); } } }
1.8 LruCache
实现 Cache 接口,基于最少使用的淘汰机制 的 Cache 实现类, 所在包: org.apache.ibatis.cache.decorators.LruCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 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); return delegate.getObject(key); } @Override public Object removeObject (Object key) { keyMap.remove(key); return delegate.removeObject(key); } @Override public void clear () { delegate.clear(); keyMap.clear(); } private void cycleKeyList (Object key) { keyMap.put(key, key); if (eldestKey != null ) { delegate.removeObject(eldestKey); eldestKey = null ; } } }
1.9 WeakCache
实现 Cache 接口,基于 java.lang.ref.WeakReference
的 Cache 实现类, 所在包: org.apache.ibatis.cache.decorators.WeakCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 public class WeakCache implements Cache { private final Deque<Object> hardLinksToAvoidGarbageCollection; private final ReferenceQueue<Object> queueOfGarbageCollectedEntries; private final Cache delegate; private int numberOfHardLinks; private final ReentrantLock lock = new ReentrantLock (); public WeakCache (Cache delegate) { this .delegate = delegate; this .numberOfHardLinks = 256 ; this .hardLinksToAvoidGarbageCollection = new LinkedList <>(); this .queueOfGarbageCollectedEntries = new ReferenceQueue <>(); } @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 WeakEntry (key, value, queueOfGarbageCollectedEntries)); } @Override public Object getObject (Object key) { Object result = null ; @SuppressWarnings("unchecked") WeakReference<Object> weakReference = (WeakReference<Object>) delegate.getObject(key); if (weakReference != null ) { result = weakReference.get(); if (result == null ) { delegate.removeObject(key); } else { lock.lock(); try { hardLinksToAvoidGarbageCollection.addFirst(result); if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) { hardLinksToAvoidGarbageCollection.removeLast(); } } finally { lock.unlock(); } } } return result; } @Override public Object removeObject (Object key) { removeGarbageCollectedItems(); @SuppressWarnings("unchecked") WeakReference<Object> weakReference = (WeakReference<Object>) delegate.removeObject(key); return weakReference == null ? null : weakReference.get(); } @Override public void clear () { lock.lock(); try { hardLinksToAvoidGarbageCollection.clear(); } finally { lock.unlock(); } removeGarbageCollectedItems(); delegate.clear(); } private void removeGarbageCollectedItems () { WeakEntry sv; while ((sv = (WeakEntry) queueOfGarbageCollectedEntries.poll()) != null ) { delegate.removeObject(sv.key); } } private static class WeakEntry extends WeakReference <Object> { private final Object key; private WeakEntry (Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) { super (value, garbageCollectionQueue); this .key = key; } } }
1.10 SoftCache
实现 Cache 接口,基于 java.lang.ref.SoftReference
的 Cache 实现类, 所在包: org.apache.ibatis.cache.decorators.SoftCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 public class SoftCache implements Cache { private final Deque<Object> hardLinksToAvoidGarbageCollection; private final ReferenceQueue<Object> queueOfGarbageCollectedEntries; private final Cache delegate; private int numberOfHardLinks; private final ReentrantLock lock = new ReentrantLock (); public SoftCache (Cache delegate) { this .delegate = delegate; this .numberOfHardLinks = 256 ; this .hardLinksToAvoidGarbageCollection = new LinkedList <>(); this .queueOfGarbageCollectedEntries = new ReferenceQueue <>(); } @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") SoftReference<Object> softReference = (SoftReference<Object>) delegate.getObject(key); if (softReference != null ) { result = softReference.get(); if (result == null ) { delegate.removeObject(key); } else { lock.lock(); try { hardLinksToAvoidGarbageCollection.addFirst(result); if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) { hardLinksToAvoidGarbageCollection.removeLast(); } } finally { lock.unlock(); } } } return result; } @Override public Object removeObject (Object key) { removeGarbageCollectedItems(); @SuppressWarnings("unchecked") SoftReference<Object> softReference = (SoftReference<Object>) delegate.removeObject(key); return softReference == null ? null : softReference.get(); } @Override public void clear () { lock.lock(); try { hardLinksToAvoidGarbageCollection.clear(); } finally { lock.unlock(); } removeGarbageCollectedItems(); delegate.clear(); } 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; } } }
2. CacheKey
因为 MyBatis 中的缓存键不是一个简单的 String ,而是通过多个对象组成 , 所以 CacheKey 可以理解成将多个对象放在一起,计算其缓存键
构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 private static final long serialVersionUID = 1146682552656046210L ; public static final CacheKey NULL_CACHE_KEY = new CacheKey () { private static final long serialVersionUID = 1L ; @Override public void update (Object object) { throw new CacheException ("Not allowed to update a null cache key instance." ); } @Override public void updateAll (Object[] objects) { throw new CacheException ("Not allowed to update a null cache key instance." ); } };private static final int DEFAULT_MULTIPLIER = 37 ;private static final int DEFAULT_HASHCODE = 17 ;private final int multiplier;private int hashcode;private long checksum;private int count;private List<Object> updateList; public CacheKey () { this .hashcode = DEFAULT_HASHCODE; this .multiplier = DEFAULT_MULTIPLIER; this .count = 0 ; this .updateList = new ArrayList <>(); } public CacheKey (Object[] objects) { this (); updateAll(objects); }
updateAll
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public void updateAll (Object[] objects) { for (Object o : objects) { update(o); } } public void update (Object object) { int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object); count++; checksum += baseHashCode; baseHashCode *= count; hashcode = multiplier * hashcode + baseHashCode; updateList.add(object); }
hashcode & equals
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Override public int hashCode () { return hashcode; } @Override public boolean equals (Object object) { if (this == object) { return true ; } if (!(object instanceof CacheKey)) { return false ; } final CacheKey cacheKey = (CacheKey) object; if ((hashcode != cacheKey.hashcode) || (checksum != cacheKey.checksum) || (count != cacheKey.count)) { return false ; } for (int i = 0 ; i < updateList.size(); i++) { Object thisObject = updateList.get(i); Object thatObject = cacheKey.updateList.get(i); if (!ArrayUtil.equals(thisObject, thatObject)) { return false ; } } return true ; }
clone
1 2 3 4 5 6 7 8 @Override public CacheKey clone () throws CloneNotSupportedException { CacheKey clonedCacheKey = (CacheKey) super .clone(); clonedCacheKey.updateList = new ArrayList <>(updateList); return clonedCacheKey; }
NullCacheKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static final CacheKey NULL_CACHE_KEY = new CacheKey () { private static final long serialVersionUID = 1L ; @Override public void update (Object object) { throw new CacheException ("Not allowed to update a null cache key instance." ); } @Override public void updateAll (Object[] objects) { throw new CacheException ("Not allowed to update a null cache key instance." ); } };