Cache

作者: 93张先生 | 来源:发表于2020-09-12 00:01 被阅读0次

    Cache

    • MyBatis 中的缓存是两层结构的,分为一级缓存、二级缓存,但在本质上是相同的,它们使用的都是 Cache 接口的实现。
    • Cache 使用了装饰器模式,为 Cache 装饰了多个功能。
    • 一级缓存是 PerpetualCache 对象,二级缓存是在 PerpetualCache 基础上装饰了其他功能。
    image.png

    Cache 接口

    public interface Cache {
    
      /**
       * 该缓存对象的Id
       * @return The identifier of this cache
       */
      String getId();
    
      /**
       * 想缓存中存入数据
       * @param key Can be any object but usually it is a {@link CacheKey}
       * @param value The result of a select.
       */
      void putObject(Object key, Object value);
    
      /**
       * 根据指定的 key 查找结果
       * @param key The key
       * @return The object stored in the cache.
       */
      Object getObject(Object key);
    
      /**
       * 删除 key 的缓存
       * As of 3.3.0 this method is only called during a rollback
       * for any previous value that was missing in the cache.
       * This lets any blocking cache to release the lock that
       * may have previously put on the key.
       * A blocking cache puts a lock when a value is null
       * and releases it when the value is back again.
       * This way other threads will wait for the value to be
       * available instead of hitting the database.
       *
       *
       * @param key The key
       * @return Not used
       */
      Object removeObject(Object key);
    
      /**
       * 清空缓存
       * Clears this cache instance.
       */
      void clear();
    
      /**
       * 缓存对象个数
       * Optional. This method is not called by the core.
       *
       * @return The number of elements stored in the cache (not its capacity).
       */
      int getSize();
    
      /**
       * 获取读写锁
       * Optional. As of 3.2.6 this method is no longer called by the core.
       * <p>
       * Any locking needed by the cache must be provided internally by the cache provider.
       *
       * @return A ReadWriteLock
       */
      default ReadWriteLock getReadWriteLock() {
        return null;
      }
    
    }
    

    PerpetualCache

    PerpetualCache 永久的缓存,一级缓存(LocalCache)和二级缓存的默认缓存。内部通过 HashMap 对象进行数据缓存,并重写了 equals 和 hashCode 方法。

    public class PerpetualCache implements Cache {
    
      private final String id;
    
      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 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();
      }
    
    }
    

    LruCache

    最近最少使用算法

    LinkedHashMap.accessOrder 参数为 true,代表访问顺序,为 false 代表插入顺序。

    public class LruCache implements Cache {
    
      private final Cache delegate;
      // LinkedHashMap<Object,Object> 类型对象,它是一个有序的 HashMap,用于记录 key 最近的使用情况
      private Map<Object, Object> keyMap;
      // 记录最少被使用的缓存项的 key
      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();
      }
      /** 重新设置缓存大小
       *
       * https://colobu.com/2015/09/07/LRU-cache-implemented-by-Java-LinkedHashMap/
       * https://juejin.im/post/6844903917524893709
       */
      public void setSize(final int size) {
        // 重新设置缓存大小,会重置 keyMap 字段
        // true 参数 代表访问顺序,LinkedHashMap.get(),会改变其记录的顺序
        keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
          private static final long serialVersionUID = 4267176411845948333L;
    
          // 当调用 LinkedHashMap.put() 方法时,会调用该方法
          @Override
          protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
            boolean tooBig = size() > size;
            if (tooBig) {
              // 如果已达到缓存上限,则更新 eldestKey 字段,后面会删除该项
              eldestKey = eldest.getKey();
            }
            return tooBig;
          }
        };
      }
    
      /**
       * 存入缓存
       * @param key Can be any object but usually it is a {@link CacheKey}
       * @param value The result of a select.
       */
      @Override
      public void putObject(Object key, Object value) {
        delegate.putObject(key, value);
        // 删除最久为使用缓存项
        cycleKeyList(key);
      }
    
      @Override
      public Object getObject(Object key) {
        // 修改 LinkedHashMap 中记录的顺序
        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();
      }
    
      /**
       *
       * @param key
       */
      private void cycleKeyList(Object key) {
        keyMap.put(key, key);
        if (eldestKey != null) {
          delegate.removeObject(eldestKey);
          eldestKey = null;
        }
      }
    
    }
    

    FifoCache

    先进先出缓存,使用 LinkedList 来实现先进先出

    public class FifoCache implements Cache {
    
      private final Cache delegate;
      // 用于记录 key 进入缓存先后顺序,使用的是 LinkedList<Object> 类型的集合对象
      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) {
        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);
        }
      }
    
    }
    

    相关文章

      网友评论

        本文标题:Cache

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