创建型
建造者模式,工厂模式
我们在单独Mybatis框架执行SQL语句的时候,需要获得SqlSession实例来直接执行已映射的 SQL 语句,在获得SqlSession实例的过程中,就使用了建造者模式和工厂模式。我们来看看一下调用过程:
1 String resource = "org/mybatis/example/mybatis-config.xml"; 2 InputStream inputStream = Resources.getResourceAsStream(resource); 3 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 4 5 try (SqlSession session = sqlSessionFactory.openSession()) { 6 Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101); 7 }
这里的Resource类使用了简单工厂模式,通过xml配置文件获得输入流,不过今天我想重点介绍一下SqlSessionFactoryBuilder类和SqlSessionFactory接口,他们分别使用了建造者模式和工厂模式。传统的建造者模式有两个重要的角色:建造者和指导者,将责任进行分割,可在实际的使用中往往只有一个建造者类调用重载的build()方法创建对象,建造者模式解决的问题是某些参数可能是可选的,避免被迫定义所有参数创建对象。DefaultSqlSessionFactory类使用了工厂模式,通过不同的配置产生不同的SqlSession类执行SQL语句。
单例模式
ErrorContext是MyBatis中用于记录线程范围内执行环境错误信息的单例对象。每个线程在执行数据库操作时,都会有一个对应的ErrorContext对象来记录当前执行的上下文信息和错误信息。ErrorContext对象被设计成线程范围内的单例,这意味着每个线程只会有一个ErrorContext对象,并且这个对象可以被整个线程共享。在多线程环境下,使用单例模式可以保证每个线程都能够独立地记录自己的执行环境错误信息,能够避免了线程之间信息错误传递。在下面的代码中,ErrorContext有私有的构造方法,同时具有instance()方法提供全局唯一访问点,而且从方法得知这是一个懒汉模式。
ErrorContext部分源码如下:
1 // 将自身存储进ThreadLocal,从而进行线程间的隔离 2 private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>(); 3 4 private ErrorContext() { 5 } 6 /** 7 * 从ThreadLocal取出已经实例化的ErrorContext,或者实例化一个ErrorContext放入ThreadLocal 8 * @return ErrorContext实例 9 */ 10 public static ErrorContext instance() { 11 ErrorContext context = LOCAL.get(); 12 if (context == null) { 13 context = new ErrorContext(); 14 LOCAL.set(context); 15 } 16 return context; 17 }
结构型
适配器模式
适配器模式可以解决兼容性问题,在Mybatsi的logging包中,有一个Log接口,该接口定义了MyBatis直接使用的日志方法,即目标类。
1 public interface Log { 2 boolean isDebugEnabled(); 3 boolean isTraceEnabled(); 4 void error(String var1, Throwable var2); 5 void error(String var1); 6 void debug(String var1); 7 void trace(String var1); 8 void warn(String var1); 9 }
实现该接口的适配器类有多个,比如对于Log4jImpl的实现来说,该实现持有了org.apache.log4j.Logger的实例,然后所有的日志方法,均委托该实例来实现。
1 import org.apache.ibatis.logging.Log; 2 import org.apache.log4j.Level; 3 import org.apache.log4j.Logger; 4 public class Log4jImpl implements Log { 5 private static final String FQCN = Log4jImpl.class.getName(); 6 private final Logger log; 7 public Log4jImpl(String clazz) { 8 this.log = Logger.getLogger(clazz); 9 } 10 public boolean isDebugEnabled() { 11 return this.log.isDebugEnabled(); 12 } 13 public boolean isTraceEnabled() { 14 return this.log.isTraceEnabled(); 15 } 16 public void error(String s, Throwable e) { 17 this.log.log(FQCN, Level.ERROR, s, e); 18 } 19 public void error(String s) { 20 this.log.log(FQCN, Level.ERROR, s, (Throwable)null); 21 } 22 public void debug(String s) { 23 this.log.log(FQCN, Level.DEBUG, s, (Throwable)null); 24 } 25 public void trace(String s) { 26 this.log.log(FQCN, Level.TRACE, s, (Throwable)null); 27 } 28 public void warn(String s) { 29 this.log.log(FQCN, Level.WARN, s, (Throwable)null); 30 } 31 }
装饰者模式
在MyBatis中,缓存的功能由Cache接口(抽象构件)定义。整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(具体构建)永久缓存实现,然后通过一系列的装饰器来对PerpetualCache进行缓存策略的增强。
-
抽象组件:
Cache
接口,定义了缓存接口的基本方法。 -
具体组件:
PerpetualCache
类,实现了Cache
接口,提供了缓存的基本实现。 -
具体装饰者:
LruCache
类、ScheduledCache
类、LoggingCache
类等,实现了Cache
类并实现了其抽象方法,提供了具体的缓存增强功能。
1 public interface Cache { 2 ......... 3 void putObject(Object var1, Object var2); 4 .......... 5 } 6 7 public class PerpetualCache implements Cache { 8 ....... 9 public void putObject(Object key, Object value) { 10 this.cache.put(key, value); 11 } 12 ....... 13 } 14 //在具体装饰类中对具体构件对象进行了功能扩充,在putObject方法中实现了先进先出策略。 15 public class FifoCache implements Cache { 16 private final Cache delegate; 17 private final Deque<Object> keyList; 18 private int size; 19 public FifoCache(Cache delegate) { 20 this.delegate = delegate; 21 this.keyList = new LinkedList(); 22 this.size = 1024; 23 } 24 ......... 25 public void putObject(Object key, Object value) { 26 this.cycleKeyList(key); 27 this.delegate.putObject(key, value); 28 } 29 ....... 30 private void cycleKeyList(Object key) { 31 this.keyList.addLast(key); 32 if (this.keyList.size() > this.size) { 33 Object oldestKey = this.keyList.removeFirst(); 34 this.delegate.removeObject(oldestKey); 35 } 36 } 37 }
组合模式
Mybatis中的SqlNode是使用组合模式实现的。SqlNode是一个抽象类,它有两个重要的子类:MixedSqlNode和TextSqlNode。MixedSqlNode代表一个混合类型的SqlNode,包含了多个SqlNode,它的作用是将多个SqlNode组合成一个整体,通过递归调用其子节点的apply方法来完成SQL语句的拼接。TextSqlNode代表一个文本类型的SqlNode,它可以包含一个动态的表达式,通过参数的替换来生成最终的SQL语句片段。在解析Mapper XML文件时,Mybatis会将每个SQL语句解析为一个SqlNode树,然后通过递归调用SqlNode的apply方法来遍历整个树,最终将所有的SqlNode组合成一个完整的SQL语句。
代理模式
代理模式可以认为是MyBatis核心使用的模式,在 MyBatis 中,每个 Mapper 接口都需要有一个对应的 Mapper 映射文件,用于描述 SQL 语句以及 SQL 语句与接口方法的映射关系。在运行时,MyBatis 会根据接口定义创建一个代理对象,该代理对象实现了该接口的所有方法,并将方法调用转换为执行对应的 SQL 语句。这里的代理对象就是使用 JDK 动态代理生成的。
行为型
模板方法模式
Executor 是 MyBatis 的核心接口之一,定义了数据库操作的基本方法,其类图如下:
BaseExecutor 类中的 query() 方法会先创建 CacheKey 对象,并根据 CacheKey 对象查找一级缓存,如果缓存命中则返回缓存中记录的结果对象,如果未命中则查询数据库得到结果集,之后将结果集映射成结果对象并保存到一级缓存中,同时返回结果对象。
doUpdate、doFlushStatements、doQuery 和 doQueryCursor 这几个方法就是交由子类来实现的,也就是说继承 BaseExecutor 的子类只需要实现这 4 个基本方法来完成数据库的相关操作即可。
BaseExecutor 的子类有 SimpleExecutor、ReuseExecutor、BatchExecutor类。
-
SimpleExecutor,每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
-
ReuseExecutor,执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。
-
BatchExecutor,将所有sql都添加到批处理中,它缓存了多个Statement对象,等待统一执行(即调用executeBatch()方法后)。
迭代器模式
DefaultCursor 实现了 Cursor 接口,而Cursor接口实现了Iterable接口,Iterable接口中有Iterator方法,DefaultCursor 类定义了一个成员变量 cursorIterator,其类型为 CursorIterator,并在iterator方法中进行返回。而CursorIterator是DefaultCursor 的一个内部类,实现了 JDK 中的 Iterator 接口。标签:log,ErrorContext,void,接口,Mybatis,设计模式,public,String From: https://www.cnblogs.com/RQfreefly/p/17376761.html