Mybatis深刻源碼分析之基於裝飾模式純手寫一級,二級,三級緩存

寫在前面:設計模式源於生活,而又高於生活!

什麼是裝飾者模式設計模式

不改變原有對象的基礎上附加功能,相比生成子類更靈活。緩存

裝飾者模式應用場景安全

Mybatis緩存,過濾器,網關控制,P2P分控審批app

裝飾者模式定義源碼分析

(1)抽象組件:定義一個抽象接口,來規範準備附加功能的類ui

(2)具體組件:將要被附加功能的類,實現抽象構件角色接口this

(3)抽象裝飾者:持有對具體構件角色的引用並定義與抽象構件角色一致的接口spa

(4)具體裝飾:實現抽象裝飾者角色,負責對具體構件添加額外功能。.net

裝飾者代碼實現

定義一個接口debug

public interface ComponentCatch {
    /**
     * 定義共同行爲的方法標準
     */
    Object getCatch(String key);
    void putCatch(String key,Object value);
}

定義被裝飾角色

/**
 * 【一級緩存】,FirstCatch【被裝飾的類】
 */
public class FirstCatch implements ComponentCatch {
    //假裝成一級緩存
    HashMap firstCatchMap=new HashMap();

    public FirstCatch() {
        firstCatchMap.put("1","xuyu");
    }
    public Object getCatch(String key) {
        Object value = firstCatchMap.get(key);
        System.out.println(">>>>>>>調用一級緩存查詢數據");
        return value;
    }

    public void putCatch(String key, Object value) {
        firstCatchMap.put(key,value);
    }
}

定義抽象裝飾角色

/**
 * 抽象裝飾者:AbstractDecorator,定義【被裝飾者】與【具體裝飾者】共同行爲
 */
public abstract class AbstractDecorator implements ComponentCatch {
    protected ComponentCatch baseCatch;

    public AbstractDecorator(ComponentCatch baseCatch) {
        this.baseCatch = baseCatch;
    }
    public Object getCatch(String key) {
        return baseCatch.getCatch(key);
    }
}

定義具體裝飾角色

/**
 * 二級緩存:SecondCatch,【裝飾者】
 * SecondCatch:在不改變原有一級緩存基礎之上搭建二級緩存
 */
public class SecondCatch extends AbstractDecorator {
    //假裝成二級緩存
    HashMap secondCatchMap=new HashMap();

    public SecondCatch(ComponentCatch baseCatch) {
        super(baseCatch);
    }

    public Object getCatch(String key) {
        System.out.println(">>>>>>>調用二級緩存查詢數據");
        //先查詢二級緩存
        Object secondValue = secondCatchMap.get(key);
        //若是二級緩存沒有,再查詢一級緩存
        if(secondValue==null){
            Object firstValue = super.getCatch(key);
            //若是一級緩存有的話
            if(firstValue!=null){
                //將一級緩存緩存到二級緩存
                secondCatchMap.put(key,firstValue);
                secondValue=firstValue;
            }
        }
        return secondValue;
    }
    public void putCatch(String key, Object value) {
    }

}
/**
 * 三級緩存【裝飾者】
 * ThiredCatch:在不改變原有二級緩存的基礎之上搭建三級緩存
 */
public class ThiredCatch extends AbstractDecorator {
    //假裝成三級緩存
    HashMap thiredCatchMap=new HashMap();

    public ThiredCatch(ComponentCatch baseCatch) {
        super(baseCatch);
    }
    public void putCatch(String key, Object value) {
    }
    public Object getCatch(String key) {
        System.out.println(">>>>>>>調用三級緩存查詢數據");
        //先查詢三級緩存
        Object thiredValue = thiredCatchMap.get(key);
        //若是三級緩存沒有,再查詢二級緩存,若是二級緩存爲空的話,再查詢一級緩存
        if(thiredValue==null){
            Object secondValue = super.getCatch(key);
            //若是二級緩存不爲空
            if(secondValue!=null){
                //將二級緩存緩存到三級緩存
                thiredCatchMap.put(key,secondValue);
                thiredValue=secondValue;
            }
        }
        return thiredValue;
    }
}

獲取裝飾類

public class FactoryCatch {
    public static ComponentCatch getComponentCatch(){
        ThiredCatch thiredCatch = new ThiredCatch(new SecondCatch(new FirstCatch()));
        return thiredCatch;
    }
    public static void main(String[] args) {
        ComponentCatch getComponentCatch=getComponentCatch();
        Object value1 = getComponentCatch.getCatch("1");
        System.out.println("value1:"+value1);
        System.out.println("###########################");
        Object value2 = getComponentCatch.getCatch("1");
        System.out.println("value2:"+value2);
    }
}

輸出結果

>>>>>>>調用三級緩存查詢數據
>>>>>>>調用二級緩存查詢數據
>>>>>>>調用一級緩存查詢數據
value1:xuyu
###########################
>>>>>>>調用三級緩存查詢數據
value2:xuyu

Mybatis源碼分析裝飾者設計模式

源碼分析圖

部分源碼

public Cache useNewCache(Class<? extends Cache> typeClass,
      Class<? extends Cache> evictionClass,
      Long flushInterval,
      Integer size,
      boolean readWrite,
      boolean blocking,
      Properties props) {
    typeClass = valueOrDefault(typeClass, PerpetualCache.class);
    evictionClass = valueOrDefault(evictionClass, LruCache.class);
    Cache cache = new CacheBuilder(currentNamespace)
        .implementation(typeClass)
         //添加二級緩存
        .addDecorator(evictionClass)
        .clearInterval(flushInterval)
        .size(size)
        .readWrite(readWrite)
        .blocking(blocking)
        .properties(props)
        .build();
    configuration.addCache(cache);
    currentCache = cache;
    return cache;
  }
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    //獲取二級緩存
    Cache cache = ms.getCache();
    //判斷二級緩存是否存在
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }
public Object getObject(Object key) {
    requests++;
    //這裏獲取二級緩存
    final Object value = delegate.getObject(key);
    if (value != null) {
      hits++;
    }
    if (log.isDebugEnabled()) {
      log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio());
    }
    return value;
  }

總結:

裝飾模式和代理模式區別?

代理模式:在方法以前和以後實現處理,在方法上實現加強,隱藏真實方法的真實性,保證安全。

裝飾模式:不改變原有的功能,實現加強,不斷新增不少裝飾。

版權@須臾之餘https://my.oschina.net/u/3995125

本文參考:螞蟻課堂:http://www.mayikt.com

相關文章
相關標籤/搜索