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

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