Mybatis(十):源码分析-各种缓存装饰类

Mybatis缓存的设计,通过Cache接口实现类:

  • PerpetualCache:永久缓存,只有这唯一一个基础实现(org.apache.ibatis.cache.impl)其他实现类全都是装饰模式(org.apache.ibatis.cache.decorators)持有另一个缓存对象;
  • PerpetualCache里面就是维护着一个本地的HashMap,所以不支持多线程,因为没能实现接口的锁功能,而且内部的map不是并发的map;
  • FifoCache(先进先出缓存策略的缓存装饰类):通过双向队列Deque维护一个缓存key的列表,在添加缓存的时候检查队列大小,超过队列设定最大值则采用先进先出移除缓存key和缓存委托对象中的存储。
  • LruCache(最近最少使用的缓存策略的缓存装饰类):通过LinkedHashMap双链回环循环链表的构造LRU算法链表,利用元素插入后总是会执行removeEldestEntry检查链表存储大小,来删除最近最少使用的缓存项key。
  • SoftCache(软引用回收策略缓存装饰类):通过LinkedList链表实现对缓存value数据的强引用ReferenceQueue队列实现对缓存value的软饮用,添加缓存委托对象数据时使用对缓存数据value的软饮用,当获取缓存项的数据不为null时,将软应用的缓存数据同时放到强引用的LinkedLik链表中变成强引用,当强引用链表大小大于numberOfHardLinks存储大小时,按照先进先出删除强引用链表移除先进入的缓存数据。然后在指定操作时机通过removeGarbageCollectedItems函数,移除被垃圾回收的键,和vlaue。软引用只有当内存不足时才会被垃圾收集器回收
  • WeakCache(弱引用回收策略缓存装饰类):同SoftCache,通过LinkedList链表实现对缓存value数据的强引用WeakReference队列实现对缓存value的弱饮用,弱引用的对象一旦被垃圾收集器发现,则会被回收,无论内存是否足够。
  • LoggingCache(日志功能装饰类,用于记录缓存的命中率):通过内部记录缓存请求次数缓存命中次数,在debug模式下面输出命中率日志。
  • ScheduledCache(定时清空Cache类):通过记录定时清空时间间隔和上次清空时间,来定时清空Cache,但是并没有开始一个定时任务,而是在使用Cache的时候,才去检查计算时间是否到了。
  • SerializedCache(序列化功能,将值序列化后存到缓存中):序列化缓存数据功能,将存储数据序列化后存到缓存中,缓存返回时进行反序列化返回一份实例的Copy,保存线程安全。
  • SynchronizedCache(同步的缓存Cache类):实现比较简单,直接使用synchronized修饰缓存操作的各种方法
  • TransactionalCache(二级缓存的事务缓存类):装饰了二级缓存对象;事务中需要进行二级缓存的各类数据保存在HashMap中,在事务提交后才会真正刷新到二级缓存中;或事务回退后被丢弃,对缓存没有影响。

FifoCache(先进先出缓存策略的缓存装饰类):

// FifoCache 源码
package org.apache.ibatis.cache.decorators;

public class FifoCache implements Cache {
  // 缓存委托对象,真正缓存存储的对象
  private final Cache delegate;
  // 维护先进先出策略的队列,用来存储缓存项key的队列,key一般为CacheKey
  // Deque是Queue的子接口,且是双向队列,它支持从两个端点方向检索和插入元素
  // 因此Deque既可以支持FIFO形式也可以支持LIFO形式
  private final Deque<Object> keyList;
  // 最大缓存树,队列的大小,初始化时为1024个
  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) {
    // 缓存项key列表周期检查函数
    cycleKeyList(key);
    // 缓存委托对象添加缓存数据
    delegate.putObject(key, value);
  }
  // 获取指定缓存项key的缓存,通过缓存委托对象
  @Override
  public Object getObject(Object key) {
    return delegate.getObject(key);
  }
  // 删除指定缓存项key的缓存,通过缓存委托对象
  @Override
  public Object removeObject(Object key) {
    return delegate.removeObject(key);
  }
  // 清空缓存
  @Override
  public void clear() {
    // 清空缓存/队列
    delegate.clear();
    keyList.clear();
  }
  // 缓存项key列表周期检查函数
  private void cycleKeyList(Object key) {
    keyList.addLast(key);
    // 队列大小超过缓存最大数,则队首元素出列,然后删除缓存委托对象中的key相关缓存
    if (keyList.size() > size) {
      Object oldestKey = keyList.removeFirst();
      delegate.removeObject(oldestKey);
    }
  }

}

LruCache(最近最少使用的缓存策略的缓存装饰类):

// LruCache 源码
package org.apache.ibatis.cache.decorators;

public class LruCache implements Cache {
  // 缓存委托对象,真正缓存存储的对象
  private final Cache delegate;
  // Map用来记录每个key使用情况的存储Map
  private Map<Object, Object> keyMap;
  // 记录keyMap中最近最少使用的元素的key
  private Object eldestKey;

  public LruCache(Cache delegate) {
    this.delegate = delegate;
    // 初始化LRU链表
    setSize(1024);
  }

  @Override
  public String getId() {
    return delegate.getId();
  }

  @Override
  public int getSize() {
    return delegate.getSize();
  }
  
  // 每次调用该方法,都会重新新建一个LinkeHashMap实例对赋值给keyMap
  public void setSize(final int size) {
    // initialCapacity -> size 初始存储大小
    // loadFactor -> .75F 默认负载因子(0.75),当容量不够时用于扩容计算,按照capacity*loadFactor取整后增长
    // accessOrder -> LRU顺序
    // true: 按访问顺序构造LRU内部链表,通过get方法调用排序,最近最少访问的排在最前面, 最多访问的排在后面. 迭代整个值是按链表从后往前的方式
    // false: 默认值,表示按照插入顺序存储,按照调用put方法插入的顺序进行排序的
    keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
      private static final long serialVersionUID = 4267176411845948333L;

      @Override
      // 钩子方法,由业务自己实现,Map在元素插入后总是会执行,返回结果为true则删除eldest,默认返回false
      // accessOrder为true时,返回true则删除最不经常使用的元素
      protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
        // 链表的大小大于设定的存储容量
        boolean tooBig = size() > size;
        if (tooBig) {
          // 记录最近最少使用的元素的key
          eldestKey = eldest.getKey();
        }
        // 如果为true,则删除记录最近最少使用的元素eldest
        return tooBig;
      }
    };
  }

  @Override
  public void putObject(Object key, Object value) {
    // 缓冲委托对象添加缓存
    delegate.putObject(key, value);
    // 周期性检查LRU链表
    cycleKeyList(key);
  }

  @Override
  // 获取缓存数据
  public Object getObject(Object key) {
    // 调用get方法,访问次数增加
    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) {
    // 向LRU的链表中添加元素
    keyMap.put(key, key);
    // 如果最近最少使用的元素key不为null,则删除缓存委托对象对应key的缓存数据
    if (eldestKey != null) {
      delegate.removeObject(eldestKey);
      // 置空
      eldestKey = null;
    }
  }

}

SoftCache(软引用回收策略缓存装饰类):

// SoftCache 源码
package org.apache.ibatis.cache.decorators;

// 软引用只有当内存不足时才会被垃圾收集器回收。这里的实现机制中,使用了一个链表来保证一定数量的值即使内存不足也不会被回收,但是没有保存在该链表的值则有可能会被回收
public class SoftCache implements Cache {
  // 硬列表,以避免GC, 初始化对象实例为LinkedList
  // 用于保存一定数量强引用的值
  private final Deque<Object> hardLinksToAvoidGarbageCollection;
  // 软引用队列,当被垃圾收集器回收时,会将软引用对象放入此队列
  private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;
  // 缓存委托对象,真正的缓存类
  private final Cache delegate;
  // 保存强引用值的数量,初始化为256
  private int numberOfHardLinks;

  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();
    // 将软引用作用到Value中
    delegate.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries));
  }

  @Override
  public Object getObject(Object key) {
    Object result = null;
    @SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache
    // 获取缓存数据
    SoftReference<Object> softReference = (SoftReference<Object>) delegate.getObject(key);
    if (softReference != null) {
      // 缓存数据结果
      result = softReference.get();
      if (result == null) {
        // 获取的数据结果为null,说明该缓存项的value被垃圾回收器回收,删除缓存委托对象对应的缓存项
        delegate.removeObject(key);
      } else {
        // 获取的数据结果不为null,将这个数据value放入强引用队列中,则value被强引用,则不会当内存不足时被垃圾收集器回收
        // See #586 (and #335) modifications need more than a read lock
        synchronized (hardLinksToAvoidGarbageCollection) {
          // 存入结果value到强引用链表(numberOfHardLinks默认256元素),防止被垃圾回收
          hardLinksToAvoidGarbageCollection.addFirst(result);
          // 强引用队列会判断当前可容纳的数量,超过了就采用先进先出的策略进行移除
          if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
            // 移除的value再次变为弱引用的对象,当内存不足时会被垃圾收集器回收
            hardLinksToAvoidGarbageCollection.removeLast();
          }
        }
      }
    }
    return result;
  }

  @Override
  public Object removeObject(Object key) {
    // 移除被垃圾收集器回收的键值
    removeGarbageCollectedItems();
    return delegate.removeObject(key);
  }

  @Override
  public void clear() {
    // 清空强引用
    synchronized (hardLinksToAvoidGarbageCollection) {
      hardLinksToAvoidGarbageCollection.clear();
    }
    // 移除被垃圾收集器回收的键值
    removeGarbageCollectedItems();
    // 清空委托缓冲对象
    delegate.clear();
  }
  // 移除被垃圾收集器回收的键值
  private void removeGarbageCollectedItems() {
    SoftEntry sv;
    // 软引用队列中存在数据时,移除缓存委托对象的缓存
    while ((sv = (SoftEntry) queueOfGarbageCollectedEntries.poll()) != null) {
      delegate.removeObject(sv.key);
    }
  }

   // 继承了SoftReference,使得传进来的value转变成软引用
   // 这里将其Value作为软引用,而不是用key,因为Key不能被回收,如果被移除的话,就会影响到整个体系,没有Key,就没有办法移除相关的值。
   // 值被回收了,将软引用对象放到队列中,根据Key调用removeObject移除该关联的键和软引用对象
  private static class SoftEntry extends SoftReference<Object> {
    // 保存与value相关联的Key,因为一旦被垃圾收集器回收,则此软引用对象会被放到关联的引用队列中
    // 这样就可以根据Key,移除该键值对
    private final Object key;

    SoftEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) {
      super(value, garbageCollectionQueue);
      this.key = key;
    }
  }

}

LoggingCache(日志功能装饰类,用于记录缓存的命中率):

// LoggingCache 源码
package org.apache.ibatis.cache.decorators;

// 日志功能装饰类,记录缓存命中率,输出命中率日志
public class LoggingCache implements Cache {

  private final Log log;
  // 缓存委托对象
  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) {
    // 统计请求次数
    requests++;
    final Object value = delegate.getObject(key);
    if (value != null) {
      // 统计缓存命中次数
      hits++;
    }
    // 开启debug模式,打印缓存的命中率
    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;
  }

}

ScheduledCache(定时清空Cache类):

// ScheduledCache 源码
package org.apache.ibatis.cache.decorators;

// 定时清空Cache类
public class ScheduledCache implements Cache {
  // 缓存委托对象
  private final Cache delegate;
  // 清空缓存数据时间间隔,初始化为间隔1小时
  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) {
    // 如果时间间隔超过缓存间隔时间直接返回null
    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;
  }

}

SerializedCache(序列化功能,将值序列化后存到缓存中):

// SerializedCache 源码
package org.apache.ibatis.cache.decorators;

// 序列化缓存数据功能,将存储数据序列化后存到缓存中,用于缓存返回一份实例的Copy,保存线程安全。
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) {
      // 调用serialize将数据序列化后在存储
      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);
    // 获取数据,进行反序列化,生产一份copy对象
    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 {
      // 在序列化的类第一次序列化的时候才会被调用
      // 遍历所支持的ClassLoader,加载对应的Class
      return Resources.classForName(desc.getName());
    }

  }
}

SynchronizedCache(同步的缓存Cache类):

// SynchronizedCache 源码
package org.apache.ibatis.cache.decorators;

public class SynchronizedCache implements Cache {

  private final Cache delegate;

  public SynchronizedCache(Cache delegate) {
    this.delegate = delegate;
  }

  @Override
  public String getId() {
    return delegate.getId();
  }

  @Override
  public synchronized int getSize() {
    return delegate.getSize();
  }

  @Override
  public synchronized void putObject(Object key, Object object) {
    delegate.putObject(key, object);
  }

  @Override
  public synchronized Object getObject(Object key) {
    return delegate.getObject(key);
  }

  @Override
  public synchronized Object removeObject(Object key) {
    return delegate.removeObject(key);
  }

  @Override
  public synchronized void clear() {
    delegate.clear();
  }

  @Override
  public int hashCode() {
    return delegate.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    return delegate.equals(obj);
  }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值