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

写在前面:设计模式源于生活,而又高于生活!

什么是装饰者模式

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

装饰者模式应用场景

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

装饰者模式定义

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

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

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

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

装饰者代码实现

定义一个接口

1public interface ComponentCatch { 2 /** 3 * 定义共同行为的方法标准 4 */ 5 Object getCatch(String key); 6 void putCatch(String key,Object value); 7}

定义被装饰角色

1/** 2 * 【一级缓存】,FirstCatch【被装饰的类】 3 */ 4public class FirstCatch implements ComponentCatch { 5 //伪装成一级缓存 6 HashMap firstCatchMap=new HashMap(); 7 8 public FirstCatch() { 9 firstCatchMap.put("1","xuyu"); 10 } 11 public Object getCatch(String key) { 12 Object value = firstCatchMap.get(key); 13 System.out.println(">>>>>>>调用一级缓存查询数据"); 14 return value; 15 } 16 17 public void putCatch(String key, Object value) { 18 firstCatchMap.put(key,value); 19 } 20}

定义抽象装饰角色

1/** 2 * 抽象装饰者:AbstractDecorator,定义【被装饰者】与【具体装饰者】共同行为 3 */ 4public abstract class AbstractDecorator implements ComponentCatch { 5 protected ComponentCatch baseCatch; 6 7 public AbstractDecorator(ComponentCatch baseCatch) { 8 this.baseCatch = baseCatch; 9 } 10 public Object getCatch(String key) { 11 return baseCatch.getCatch(key); 12 } 13}

定义具体装饰角色

1/** 2 * 二级缓存:SecondCatch,【装饰者】 3 * SecondCatch:在不改变原有一级缓存基础之上搭建二级缓存 4 */ 5public class SecondCatch extends AbstractDecorator { 6 //伪装成二级缓存 7 HashMap secondCatchMap=new HashMap(); 8 9 public SecondCatch(ComponentCatch baseCatch) { 10 super(baseCatch); 11 } 12 13 public Object getCatch(String key) { 14 System.out.println(">>>>>>>调用二级缓存查询数据"); 15 //先查询二级缓存 16 Object secondValue = secondCatchMap.get(key); 17 //如果二级缓存没有,再查询一级缓存 18 if(secondValue==null){ 19 Object firstValue = super.getCatch(key); 20 //如果一级缓存有的话 21 if(firstValue!=null){ 22 //将一级缓存缓存到二级缓存 23 secondCatchMap.put(key,firstValue); 24 secondValue=firstValue; 25 } 26 } 27 return secondValue; 28 } 29 public void putCatch(String key, Object value) { 30 } 31 32} 33 34/** 35 * 三级缓存【装饰者】 36 * ThiredCatch:在不改变原有二级缓存的基础之上搭建三级缓存 37 */ 38public class ThiredCatch extends AbstractDecorator { 39 //伪装成三级缓存 40 HashMap thiredCatchMap=new HashMap(); 41 42 public ThiredCatch(ComponentCatch baseCatch) { 43 super(baseCatch); 44 } 45 public void putCatch(String key, Object value) { 46 } 47 public Object getCatch(String key) { 48 System.out.println(">>>>>>>调用三级缓存查询数据"); 49 //先查询三级缓存 50 Object thiredValue = thiredCatchMap.get(key); 51 //如果三级缓存没有,再查询二级缓存,如果二级缓存为空的话,再查询一级缓存 52 if(thiredValue==null){ 53 Object secondValue = super.getCatch(key); 54 //如果二级缓存不为空 55 if(secondValue!=null){ 56 //将二级缓存缓存到三级缓存 57 thiredCatchMap.put(key,secondValue); 58 thiredValue=secondValue; 59 } 60 } 61 return thiredValue; 62 } 63}

获取装饰类

1public class FactoryCatch { 2 public static ComponentCatch getComponentCatch(){ 3 ThiredCatch thiredCatch = new ThiredCatch(new SecondCatch(new FirstCatch())); 4 return thiredCatch; 5 } 6 public static void main(String[] args) { 7 ComponentCatch getComponentCatch=getComponentCatch(); 8 Object value1 = getComponentCatch.getCatch("1"); 9 System.out.println("value1:"+value1); 10 System.out.println("###########################"); 11 Object value2 = getComponentCatch.getCatch("1"); 12 System.out.println("value2:"+value2); 13 } 14}

输出结果

>>>>>>>调用三级缓存查询数据
>>>>>>>调用二级缓存查询数据
>>>>>>>调用一级缓存查询数据
value1:xuyu
###########################
>>>>>>>调用三级缓存查询数据
value2:xuyu

Mybatis源码分析装饰者设计模式

源码分析图

部分源码

1public Cache useNewCache(Class<? extends Cache> typeClass, 2 Class<? extends Cache> evictionClass, 3 Long flushInterval, 4 Integer size, 5 boolean readWrite, 6 boolean blocking, 7 Properties props) { 8 typeClass = valueOrDefault(typeClass, PerpetualCache.class); 9 evictionClass = valueOrDefault(evictionClass, LruCache.class); 10 Cache cache = new CacheBuilder(currentNamespace) 11 .implementation(typeClass) 12 //添加二级缓存 13 .addDecorator(evictionClass) 14 .clearInterval(flushInterval) 15 .size(size) 16 .readWrite(readWrite) 17 .blocking(blocking) 18 .properties(props) 19 .build(); 20 configuration.addCache(cache); 21 currentCache = cache; 22 return cache; 23 } 24 25 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) 26 throws SQLException { 27 //获取二级缓存 28 Cache cache = ms.getCache(); 29 //判断二级缓存是否存在 30 if (cache != null) { 31 flushCacheIfRequired(ms); 32 if (ms.isUseCache() && resultHandler == null) { 33 ensureNoOutParams(ms, parameterObject, boundSql); 34 @SuppressWarnings("unchecked") 35 List<E> list = (List<E>) tcm.getObject(cache, key); 36 if (list == null) { 37 list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); 38 tcm.putObject(cache, key, list); // issue #578 and #116 39 } 40 return list; 41 } 42 } 43 return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); 44 } 45 46public Object getObject(Object key) { 47 requests++; 48 //这里获取二级缓存 49 final Object value = delegate.getObject(key); 50 if (value != null) { 51 hits++; 52 } 53 if (log.isDebugEnabled()) { 54 log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio()); 55 } 56 return value; 57 }

总结:

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

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

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

版权@须臾之余https://my.oschina.net/u/3995125

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

点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

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