mybatis-cache缓存包解析

概述

缓存包是mybatis对缓存的抽象和实现,可为其他模块提供缓存的支持。其设计也很值得借鉴。

在这里插入图片描述

大概分为

  • 缓存定义(抽象、异常、缓存键)
  • 缓存实现
  • 缓存装饰者

可以重点在于缓存策略装饰模式实现,可以复习复习装饰模式啦。

Cache

public interface Cache {
  String getId();
  void putObject(Object key, Object value);
  Object getObject(Object key);
  Object removeObject(Object key);
  void clear();
  int getSize();

}

缓存容器基础抽象,定义了基础的缓存操作。

在这里插入图片描述

所有缓存容器实现类。其中只有PerpetualCache是真正的缓存实现类,其余都是装饰实现类。

PerpetualCache

永不过期缓存容器,实现比较简单,最基础的单机缓存容器实现。

public class PerpetualCache implements Cache {
  // 缓存容器id
  private final String id;
  // 缓存容器载体
  private Map<Object, Object> cache = new HashMap<>();
}

缓存操作基于HashMap,非常简单。

Decorator

decorator有一个单独的子包,全部放着缓存的装饰类。

  • BlockingCache
  • FifoCache
  • loggingCache
  • LruCache
  • ScheduledCache
  • SerializedCache
  • SoftCache
  • SynchronizedCache
  • TransactionalCache
  • WeakCache

通过名字可以很容易就辨认出该实现的作用。

让我们先复习下装饰模式

img

这是装饰模式的类图

Component:抽象组件

ConcreteComponent:组件实现类

Decorator:装饰实现类,实现抽象组件,组合ConcreteComponent,并在其上额外添加功能。

好处是添加功能时无需对之前类进行修改,职责也更加清晰。

让我们来看看mybatis缓存中Decorator的实现。

FifoCache

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;
  }
}

设置初始缓存大小,使用双端队列进行控制key大小。实现也比较简单。

WeakCache

虚引用缓存,缓存的值使用虚引用包装。

又被迫复习下虚引用的知识,gc时如果发现内存不足会清楚虚引用包裹的对象。

public class WeakCache implements Cache {
  // 双端队列保存一定数量的值,避免被gc
  private final Deque<Object> hardLinksToAvoidGarbageCollection;
  // 引用队列,被gc清楚的值会放在里面
  private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;
  private final Cache delegate;
  // 队列大小
  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() {
    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") // assumed delegate cache is totally managed by this cache
    WeakReference<Object> weakReference = (WeakReference<Object>) delegate.getObject(key);
    if (weakReference != null) {
      result = weakReference.get();
      if (result == null) {
        delegate.removeObject(key);
      } else {
        hardLinksToAvoidGarbageCollection.addFirst(result);
        if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
          hardLinksToAvoidGarbageCollection.removeLast();
        }
      }
    }
    return result;
  }

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

  @Override
  public void clear() {
    hardLinksToAvoidGarbageCollection.clear();
    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;
    }
  }

}

每次操作时调用removeGarbageCollectedItems()方法,用于清楚已经被gc清除了的缓存值。

其他

还有一些策略缓存装饰几乎使用的很少,参考参考即可。

总结

缓存包 比较清晰简单,但是有借鉴的地方的。在我们业务开发时,可以也为应用设计一个独立的缓存包,后续甚至可以独立为服务,一些缓存策略也可以使用装饰模式来实现。代码肯定会比直接操作redis清晰许多。


That’s All

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章