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

Stella981
• 阅读 676

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深入源码分析之基于装饰模式纯手写一级,二级,三级缓存

部分源码

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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
3年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
00_设计模式之语言选择
设计模式之语言选择设计模式简介背景设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式(Designpattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这