疯狂的蚂蚁 JavaGuide
本文转载自: https://dwz.cn/KFgol1De 由JavaGuide整理排版。
虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开发中很少遇到,Mybatis源码中使用了大量的设计模式,阅读源码并观察设计模式在其中的应用,能够更深入的理解设计模式。
目录
面试官:“谈谈MyBatis中都用到了那些设计模式?”。
1、Builder 模式
2、工厂模式
3、单例模式
4、代理模式
5、组合模式
6、模板方法模式
7、适配器模式
8、装饰者模式
9、迭代器模式
参考资料
Mybatis至少遇到了以下的设计模式的使用:
-
Builder模式 :
例如
SqlSessionFactoryBuilder
、XMLConfigBuilder
、XMLMapperBuilder
、XMLStatementBuilder
、CacheBuilder
; -
工厂模式 :
例如
SqlSessionFactory
、ObjectFactory
、MapperProxyFactory
; -
单例模式 :例如
ErrorContext
和LogFactory
; -
代理模式 :Mybatis实现的核心,比如
MapperProxy
、ConnectionLogger
,用的jdk的动态代理;还有executor.loader
包使用了cglib或者javassist达到延迟加载的效果; -
组合模式 :例如
SqlNode
和各个子类ChooseSqlNode
等; -
模板方法模式 : 例如
BaseExecutor
和SimpleExecutor
,还有BaseTypeHandler
和所有的子类例如IntegerTypeHandler
; -
适配器模式 : 例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
-
装饰者模式 : 例如
cache
包中的cache.decorators
子包中等各个装饰者的实现; -
迭代器模式 : 例如迭代器模式
PropertyTokenizer
;
接下来挨个模式进行解读,先介绍模式自身的知识,然后解读在Mybatis中怎样应用了该模式。
1、Builder 模式Builder模式的定义是“将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。”,它属于创建类模式,一般来说,如果一个对象的构建比较复杂,超出了构造函数所能包含的范围,就可以使用工厂模式和Builder模式,相对于工厂模式会产出一个完整的产品,Builder应用于更加复杂的对象的构建,甚至只会构建产品的一个部分。《effective-java》中第2条也提到:遇到多个构造器参数时,考虑用构建者(Builder)模式。
Builder模式
在Mybatis环境的初始化过程中,SqlSessionFactoryBuilder
会调用XMLConfigBuilder
读取所有的MybatisMapConfig.xml
和所有的*Mapper.xml
文件,构建Mybatis运行的核心对象Configuration
对象,然后将该Configuration
对象作为参数构建一个SqlSessionFactory
对象。
其中XMLConfigBuilder
在构建Configuration
对象时,也会调用XMLMapperBuilder
用于读取*.Mapper
文件,而XMLMapperBuilder
会使用XMLStatementBuilder
来读取和build所有的SQL语句。
在这个过程中,有一个相似的特点,就是这些Builder会读取文件或者配置,然后做大量的XpathParser解析、配置或语法的解析、反射生成对象、存入结果缓存等步骤,这么多的工作都不是一个构造函数所能包括的,因此大量采用了Builder模式来解决。
对于builder的具体类,方法都大都用build*
开头,比如SqlSessionFactoryBuilder
为例,它包含以下方法:
SqlSessionFactoryBuilder
即根据不同的输入参数来构建SqlSessionFactory
这个工厂对象。
在Mybatis中比如SqlSessionFactory
使用的是工厂模式,该工厂没有那么复杂的逻辑,是一个简单工厂模式。
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
简单工厂模式
SqlSession
可以认为是一个Mybatis工作的核心的接口,通过这个接口可以执行执行SQL语句、获取Mappers、管理事务。类似于连接MySQL的Connection
对象。
SqlSessionFactory
可以看到,该Factory的openSession()
方法重载了很多个,分别支持autoCommit
、Executor
、Transaction
等参数的输入,来构建核心的SqlSession
对象。
在DefaultSqlSessionFactory
的默认工厂实现里,有一个方法可以看出工厂怎么产出一个产品:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call
// close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
这是一个openSession调用的底层方法,该方法先从configuration读取对应的环境配置,然后初始化TransactionFactory
获得一个Transaction
对象,然后通过Transaction
获取一个Executor
对象,最后通过configuration、Executor、是否autoCommit三个参数构建了SqlSession
。
在这里其实也可以看到端倪,SqlSession
的执行,其实是委托给对应的Executor
来进行的。
而对于LogFactory
,它的实现代码:
public final class LogFactory {
private static Constructor
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?