美文网首页
MyBatis源码解析(四) Cache模块

MyBatis源码解析(四) Cache模块

作者: 谈谈理想_ttlx | 来源:发表于2019-11-30 16:45 被阅读0次

    MyBatis的二级缓存

    MyBatis的缓存分为一级缓存和二级缓存,一级缓存是 SqlSession 级别的缓存,二级缓存是mapper级别的缓存。但是这篇博客主要是介绍mybaits中缓存接口和缓存键接口,以及一些缓存实现。

    之前写过一篇博客简单介绍了一下Hibernate的两级缓存。

    链接: https://blog.csdn.net/Let_me_tell_you/article/details/80876767

    Cache接口

    源码位置:org.apache.ibatis.cache.Cache

    缓存容器接口,自定义操作方法,其他缓存实现类需要实现这个接口。

    UML类图

    Cache接口UML类图.png

    上图中列出来的就是Cache接口的实现类,实现不同的缓存功能。

    接口的源码很简单,就是定义了一些增删改查缓存的方法,和一个获取容器中缓存数量和获得读写锁的方法。我精简了下注释,源码内容如下。Cache接口其实是一个缓存容器,有点类似于一个HashMap(有一些实现类就是使用HashMap来保存操作缓存数据的)。

    public interface Cache {
    
      /**
       * 获取标识
       */
      String getId();
    
      /**
       * 添加指定的键
       */
      void putObject(Object key, Object value);
    
      /**
       * 获取指定的键的值
       */
      Object getObject(Object key);
    
      /**
       * 删除指定的键的值
       */
      Object removeObject(Object key);
    
      /**
       * 清空缓存
       */
      void clear();
    
      /**
       * 获取容器中缓存的数量
       */
      int getSize();
    
      /**
       * 获得读写锁
       */
      default ReadWriteLock getReadWriteLock() {
        return null;
      }
    
    }
    

    PerpetualCache

    源码位置:org.apache.ibatis.cache.impl.PerpetualCache

    永不过期的缓存,使用HashMap来保存和操作数据,重写了 equals()hashCode() 方法,其他缓存操作都是直接调用的HashMap方法。

    LoggingCache

    源码位置:org.apache.ibatis.cache.decorators.LoggingCache

    这是一个支持打印日志的 Cache 实现,代码也很简单,加了一些注释。

    public class LoggingCache implements Cache {
    
      /**
       * mybaits log 对象
       */
      private final Log log;
      /**
       * 装饰的 Cache 对象
       */
      private final Cache delegate;
      /**
       * 统计请求缓存的次数
       */
      protected int requests = 0;
      /**
       * 命中缓存的次数
       */
      protected int hits = 0;
    
      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) {
        //请求次数加 1
        requests++;
        final Object value = delegate.getObject(key);
        if (value != null) {
          //命中缓存,命中次数加 1
          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);
      }
    
      /**
       * 计算命中比例
       * @return
       */
      private double getHitRatio() {
        //算法: 命中次数 / 请求缓存次数
        return (double) hits / (double) requests;
      }
    
    }
    

    BlockingCache

    源码位置:org.apache.ibatis.cache.decorators.BlockingCache

    阻塞的Cache实现类,这个实现不同的逻辑是在加锁上。当一个线程去获取缓存事,缓存不存在则会阻塞后续线程获取,当前线程则去添加缓存值,避免后续线程重复添加缓存。需要注意的是这个实现里 removeObject 方法并不是删除缓存值,而是移除锁。

    public class BlockingCache implements Cache {
    
      /**
       * 阻塞等待超时时间
       */
      private long timeout;
      /**
       * 装饰的Cache对象
       */
      private final Cache delegate;
      /**
       * 缓存键 与  ReentrantLock 对象映射
       */
      private final ConcurrentHashMap<Object, ReentrantLock> 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) {
        // despite of its name, this method is called only to release locks
        //释放该键对应的锁
        releaseLock(key);
        return null;
      }
    
      @Override
      public void clear() {
        delegate.clear();
      }
    
      /**
       * 获得 ReentrantLock 对象,如果不存在,则进行添加
       * @param key
       * @return
       */
      private ReentrantLock getLockForKey(Object key) {
        return locks.computeIfAbsent(key, k -> new ReentrantLock());
      }
    
      private void acquireLock(Object key) {
        //获得键对应的 ReentrantLock 对象
        Lock lock = getLockForKey(key);
        //获得锁,直到超时
        if (timeout > 0) {
          try {
            boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
            if (!acquired) {
              throw new CacheException("Couldn't get a lock in " + timeout + " for the key " +  key + " at the cache " + delegate.getId());
            }
          } catch (InterruptedException e) {
            throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e);
          }
        } else {
          //释放锁
          lock.lock();
        }
      }
    
      private void releaseLock(Object key) {
        //获得 ReentrantLock 对象
        ReentrantLock lock = locks.get(key);
        if (lock.isHeldByCurrentThread()) {
          //如果当前线程持有锁,进行释放
          lock.unlock();
        }
      }
    
      public long getTimeout() {
        return timeout;
      }
    
      public void setTimeout(long timeout) {
        this.timeout = timeout;
      }
    }
    

    SynchronizedCache

    源码位置:org.apache.ibatis.cache.decorators.SynchronizedCache

    同步Cache实现,内部也是使用装饰的Cache来实现缓存操作。不过这个实现在 getSize putObject getObject removeObject clear 这几个方法上添加了 synchronized关键字。

    SerializedCache

    源码位置:org.apache.ibatis.cache.decorators.SerializedCache

    支持序列化值,其实就是在添加缓存的时候对值进行序列化,获取值的时候反序列化。

    public class SerializedCache implements Cache {
      //装饰的 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) {
            //存值进行序列化
          delegate.putObject(key, serialize((Serializable) object));
        } else {
          throw new CacheException("SharedCache failed to make a copy of a non-serializable object: " + 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) {
        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());
        }
    
      }
    
    }
    

    ScheduledCache

    源码位置:org.apache.ibatis.cache.decorators.ScheduledCache

    定时清空整个 Cache 的缓存,在每次操作缓存之前判断是否全部清空缓存

    public class ScheduledCache implements Cache {
    
      /**
       * 装饰的 Cache 对象
       */
      private final Cache delegate;
      /**
       * 清空间隔,单位:毫秒
       */
      protected long clearInterval;
      /**
       * 最后清空时间,单位:毫秒
       */
      protected long lastClear;
    
      public ScheduledCache(Cache delegate) {
        this.delegate = delegate;
        //默认清空间隔 一小时
        this.clearInterval = 60 * 60 * 1000; // 1 hour
        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);
      }
    
      /**
       * 判断是否需要全部清空
       * @return
       */
      private boolean clearWhenStale() {
        if (System.currentTimeMillis() - lastClear > clearInterval) {
          //全部清空
          clear();
          return true;
        }
        return false;
      }
    
    }
    

    FifoCache

    源码位置:org.apache.ibatis.cache.decorators.FifoCache

    基于先进先出淘汰机制的Cache实现,此实现在删除缓存时并不会删除缓存key,所以旧的 key 也依旧会继续存在。

    除此之外在添加key的时候该实现也不会去判断key是否已经存在,只会判断当前长度是否超过了队列上上限,所以重复添加就会在队列里存在多个相同的key,这个不能说是bug,只能说是允许重复的key,但是如果你在使用中发现同一个key拿到的缓存不止一个,可能就需要检查一下你使用的是不是 FifoCache 实现了。

    public class FifoCache implements Cache {
    
      /**
       * 装饰的 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) {
        //循环 keyList
        cycleKeyList(key);
        delegate.putObject(key, value);
      }
    
      @Override
      public Object getObject(Object key) {
        return delegate.getObject(key);
      }
    
      @Override
      public Object removeObject(Object key) {
        //删除缓存,未清空keyList中的数据
        return delegate.removeObject(key);
      }
    
      @Override
      public void clear() {
        //清空缓存时,同时清空维护的 keyList
        delegate.clear();
        keyList.clear();
      }
    
      private void cycleKeyList(Object key) {
        //添加到 keyList
        keyList.addLast(key);
        if (keyList.size() > size) {
          //如果添加新 key 之后 ketList 的长度大于 队列上线,将队列的首位移除
          Object oldestKey = keyList.removeFirst();
          delegate.removeObject(oldestKey);
        }
      }
    
    }
    

    LruCache

    源码位置:org.apache.ibatis.cache.decorators.LruCache

    此实现是基于最少使用的淘汰机制的 Cache 实现,简单说就是当添加缓存时发现已经达到上限的时候,淘汰掉最少使用的 key 以及对应的缓存。使用 LinkedHashMap 的淘汰机制,具体源码的解析请参考下面的源码。

    public class LruCache implements Cache {
    
      /**
       * 装饰的 Cache 对象
       */
      private final Cache delegate;
      /**
       * 基于 LinkedHashMap 实现淘汰机制
       */
      private Map<Object, Object> keyMap;
      /**
       * 最老/最少被使用的键,即将被淘汰的 key
       */
      private Object eldestKey;
    
      public LruCache(Cache delegate) {
        this.delegate = delegate;
        //初始化 keyMap 对象
        setSize(1024);
      }
    
      @Override
      public String getId() {
        return delegate.getId();
      }
    
      @Override
      public int getSize() {
        return delegate.getSize();
      }
    
      /**
       * 初始化keyMap,但是此方法的权限标识是 public ,也就是说可以通过这个方法来指定 keyMap的长度,默认是1024,可以根据自己的需求来变更
       * @param size
       */
      public void setSize(final int size) {
        //LinkedHasmp的一个构造函数,当参数 accessOrder 为 true 时,即会按照访问的顺序排序,最近访问的在最前,最早访问的在最后
        keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
          private static final long serialVersionUID = 4267176411845948333L;
    
          @Override
          protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
            //重写 LinkedHashMapLinkedHashMap 的删除元素方法,当满足一定条件的时候删除元素,LinkedHashMap中默认是不删除
            //这里判断的条件就是 keyMap 长度大于初始化 keyMap 时给定的值,满足条件时将最少使用的 key 设置为待删除,
            // 等下次添加新key的时候判断 eldestKey 参数不为空则对 eldestKey 进行移除
            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();
      }
    
      private void cycleKeyList(Object key) {
        //添加 key 到keyMap中
        keyMap.put(key, key);
        //如果超过上限,则删除最少使用的可以
        if (eldestKey != null) {
          //移除 eldestKey
          delegate.removeObject(eldestKey);
          //置空
          eldestKey = null;
        }
      }
    
    }
    

    WeakCache

    源码位置:org.apache.ibatis.cache.decorators.WeakCache

    基于 java.lang.ref.WeakReference 的Cache实现类,主要是基于内部维护的一个强引用和mybatis基于 java.lang.ref.WeakReference 扩展的WeakEntry来实现缓存淘汰。在这个实现里,一样存在key多次添加会导致重复key的问题。

    public class WeakCache implements Cache {
      //强引用的键的队列
      private final Deque<Object> hardLinksToAvoidGarbageCollection;
      //被GC回收的 WeakEntry 集合,避免被 GC
      private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;
      //装饰的 Cache 对象
      private final Cache delegate;
      //hardLinksToAvoidGarbageCollection 的大小
      private int numberOfHardLinks;
    
      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() {
        //移除已经被 GC 回收的WeakEntry
        removeGarbageCollectedItems();
        return delegate.getSize();
      }
    
      public void setSize(int size) {
        this.numberOfHardLinks = size;
      }
    
      @Override
      public void putObject(Object key, Object value) {
        //移除已经被 GC 回收的 WeakEntry
        removeGarbageCollectedItems();
        //添加缓存
        delegate.putObject(key, new WeakEntry(key, value, queueOfGarbageCollectedEntries));
      }
    
      @Override
      public Object getObject(Object key) {
        Object result = null;
        @SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache
        //获得值的 WeakReference 对象
        WeakReference<Object> weakReference = (WeakReference<Object>) delegate.getObject(key);
        if (weakReference != null) {
          //获得值
          result = weakReference.get();
          if (result == null) {
            //值为空,表示已经被GC回收,移除缓存
            delegate.removeObject(key);
          } else {
            //非空,添加到 hardLinksToAvoidGarbageCollection 队列首部,未做key唯一性判断,所以存在重复添加的情况 ,避免被 GC
            hardLinksToAvoidGarbageCollection.addFirst(result);
            if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
              //如果长度超出上限,则移除队列尾部的元素
              hardLinksToAvoidGarbageCollection.removeLast();
            }
          }
        }
        return result;
      }
    
      @Override
      public Object removeObject(Object key) {
        //移除已经被 GC 回收的 WeakEntry
        removeGarbageCollectedItems();
        //移除缓存
        return delegate.removeObject(key);
      }
    
      @Override
      public void clear() {
        //清空 hardLinksToAvoidGarbageCollection
        hardLinksToAvoidGarbageCollection.clear();
        //移除已经被 GC 回收的 WeakEntry
        removeGarbageCollectedItems();
        //清空缓存
        delegate.clear();
      }
    
      /**
       * 移除已经被 GC 回收的键
       */
      private void removeGarbageCollectedItems() {
        WeakEntry sv;
        while ((sv = (WeakEntry) queueOfGarbageCollectedEntries.poll()) != null) {
          delegate.removeObject(sv.key);
        }
      }
    
      /**
       * 继承自 WeakReference ,增加缓存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;
        }
      }
    
    }
    

    SoftCache

    源码位置:org.apache.ibatis.cache.decorators.SoftCache

    基于java.lang.ref.SoftReference 的Cache实现,SoftCache内部实现了SoftEntry,其他基本上与WeakCache基本上是差不多的,只是在一些操作中会对 hardLinksToAvoidGarbageCollection 加锁。

    public class WeakCache implements Cache {
      //强引用的键的队列
      private final Deque<Object> hardLinksToAvoidGarbageCollection;
      //被GC回收的 WeakEntry 集合,避免被 GC
      private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;
      //装饰的 Cache 对象
      private final Cache delegate;
      //hardLinksToAvoidGarbageCollection 的大小
      private int numberOfHardLinks;
    
      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() {
        //移除已经被 GC 回收的WeakEntry
        removeGarbageCollectedItems();
        return delegate.getSize();
      }
    
      public void setSize(int size) {
        this.numberOfHardLinks = size;
      }
    
      @Override
      public void putObject(Object key, Object value) {
        //移除已经被 GC 回收的 WeakEntry
        removeGarbageCollectedItems();
        //添加缓存
        delegate.putObject(key, new WeakEntry(key, value, queueOfGarbageCollectedEntries));
      }
    
      @Override
      public Object getObject(Object key) {
        Object result = null;
        @SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache
        //获得值的 WeakReference 对象
        WeakReference<Object> weakReference = (WeakReference<Object>) delegate.getObject(key);
        if (weakReference != null) {
          //获得值
          result = weakReference.get();
          if (result == null) {
            //值为空,表示已经被GC回收,移除缓存
            delegate.removeObject(key);
          } else {
            //非空,添加到 hardLinksToAvoidGarbageCollection 队列首部,未做key唯一性判断,所以存在重复添加的情况 ,避免被 GC
            hardLinksToAvoidGarbageCollection.addFirst(result);
            if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
              //如果长度超出上限,则移除队列尾部的元素
              hardLinksToAvoidGarbageCollection.removeLast();
            }
          }
        }
        return result;
      }
    
      @Override
      public Object removeObject(Object key) {
        //移除已经被 GC 回收的 WeakEntry
        removeGarbageCollectedItems();
        //移除缓存
        return delegate.removeObject(key);
      }
    
      @Override
      public void clear() {
        //清空 hardLinksToAvoidGarbageCollection
        hardLinksToAvoidGarbageCollection.clear();
        //移除已经被 GC 回收的 WeakEntry
        removeGarbageCollectedItems();
        //清空缓存
        delegate.clear();
      }
    
      /**
       * 移除已经被 GC 回收的键
       */
      private void removeGarbageCollectedItems() {
        WeakEntry sv;
        while ((sv = (WeakEntry) queueOfGarbageCollectedEntries.poll()) != null) {
          delegate.removeObject(sv.key);
        }
      }
    
      /**
       * 继承自 WeakReference ,增加缓存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;
        }
      }
    
    }
    

    CachKey

    源码位置:org.apache.ibatis.cache.CacheKey

    mybaits中的缓存键,不只是单纯的String字符串,而是由多个对象组成,共同计算缓存键。CacheKey中封装了多个影响缓存的属性。

    public class CacheKey implements Cloneable, Serializable {
    
      private static final long serialVersionUID = 1146682552656046210L;
    
      //单例 空缓存键
      public static final CacheKey NULL_CACHE_KEY = new NullCacheKey();
    
      //multiplier 的值
      private static final int DEFAULT_MULTIPLYER = 37;
      //hashcode 的值
      private static final int DEFAULT_HASHCODE = 17;
    
      //hashcode求值的系数
      private final int multiplier;
      //缓存键的hashcode
      private int hashcode;
      //校验和
      private long checksum;
      //updateList 的长度
      private int count;
      // 8/21/2017 - Sonarlint flags this as needing to be marked transient.  While true if content is not serializable, this is not always true and thus should not be marked transient.
      //计算 hashcode 的对象的集合
      private List<Object> updateList;
    
      public CacheKey() {
        this.hashcode = DEFAULT_HASHCODE;
        this.multiplier = DEFAULT_MULTIPLYER;
        this.count = 0;
        this.updateList = new ArrayList<>();
      }
    
      public CacheKey(Object[] objects) {
        this();
        //基于 objects ,更新相关属性
        updateAll(objects);
      }
    
      public int getUpdateCount() {
        return updateList.size();
      }
    
      public void update(Object object) {
        //方法参数 object 的 hashcode
        int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);
    
        count++;
        //checksum 为 baseHashCode 求和
        checksum += baseHashCode;
        //计算hashcode值
        baseHashCode *= count;
        hashcode = multiplier * hashcode + baseHashCode;
        //添加 object(缓存key) 到updateList中
        updateList.add(object);
      }
    
      public void updateAll(Object[] objects) {
        //遍历 objects 数组,调用 update 方法,更新相关属性
        for (Object o : objects) {
          update(o);
        }
      }
    
      @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) {
          return false;
        }
        if (checksum != cacheKey.checksum) {
          return false;
        }
        if (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;
      }
    
      @Override
      public int hashCode() {
        return hashcode;
      }
    
      @Override
      public String toString() {
        StringJoiner returnValue = new StringJoiner(":");
        returnValue.add(String.valueOf(hashcode));
        returnValue.add(String.valueOf(checksum));
        updateList.stream().map(ArrayUtil::toString).forEach(returnValue::add);
        return returnValue.toString();
      }
    
      @Override
      public CacheKey clone() throws CloneNotSupportedException {
        //克隆 CacheKey 对象
        CacheKey clonedCacheKey = (CacheKey) super.clone();
        //创建 updateList 数组,避免原数组修改
        clonedCacheKey.updateList = new ArrayList<>(updateList);
        return clonedCacheKey;
      }
        
    }    
    

    NullCacheKey

    源码位置:org.apache.ibatis.cache.NullCacheKey

    继承自 CacheKey ,空缓存键。

    public final class NullCacheKey extends CacheKey {
    
      private static final long serialVersionUID = 3704229911977019465L;
    
      public NullCacheKey() {
        super();
      }
    
      @Override
      public void update(Object object) {
        throw new CacheException("Not allowed to update a NullCacheKey instance.");
      }
    
      @Override
      public void updateAll(Object[] objects) {
        throw new CacheException("Not allowed to update a NullCacheKey instance.");
      }
    }public final class NullCacheKey extends CacheKey {
    
      private static final long serialVersionUID = 3704229911977019465L;
    
      public NullCacheKey() {
        super();
      }
    
      @Override
      public void update(Object object) {
        throw new CacheException("Not allowed to update a NullCacheKey instance.");
      }
    
      @Override
      public void updateAll(Object[] objects) {
        throw new CacheException("Not allowed to update a NullCacheKey instance.");
      }
    }
    

    本文由博客一文多发平台 OpenWrite 发布!

    相关文章

      网友评论

          本文标题:MyBatis源码解析(四) Cache模块

          本文链接:https://www.haomeiwen.com/subject/oewowctx.html