Mybatis深入源码分析之基于装饰模式纯手写一级,二级,三级缓存

什么是装饰者模式

不改变原有对象的基础上附加功能,相比生成子类更灵活。

装饰者模式应用场景

Mybatis缓存,过滤器,网关控制,P2P分控审批

装饰者模式定义

(1)抽象组件:定义一个抽象接口,来规范准备附加功能的类

(2)具体组件:将要被附加功能的类,实现抽象构件角色接口

(3)抽象装饰者:持有对具体构件角色的引用并定义与抽象构件角色一致的接口

(4)具体装饰:实现抽象装饰者角色,负责对具体构件添加额外功能。

装饰者代码实现

定义一个接口

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源码分析装饰者设计模式

源码分析图

Mybatis深入源码分析之基于装饰模式纯手写一级,二级,三级缓存_第1张图片

部分源码

public Cache useNewCache(Class typeClass,
      Class 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  List 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 list = (List) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate. 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;
  }

总结:

装饰模式和代理模式区别?

代理模式:在方法之前和之后实现处理,在方法上实现增强,隐藏真实方法的真实性,保证安全。

装饰模式:不改变原有的功能,实现增强,不断新增很多装饰。

知识分享

本文参考:蚂蚁课堂:http://www.mayikt.com

你可能感兴趣的:(设计模式)