摘要:MyBatis源码展现了优秀的设计模式和架构思想。其运用建造者模式创建复杂对象,动态代理实现Mapper接口,装饰器动态扩展功能等。架构上采用清晰分层设计,插件化扩展机制实现开闭原则,多级缓存提升性能,面向接口编程降低耦合。这些设计理念对日常业务开发也有很大借鉴价值。
通过以下系列博文,我们熟悉了Mybatis源码实现的诸多细节,如Executor接口及其实现、缓存体系、自定义插件等。
- Mybatis入门到精通 一
- Mybatis的Executor和缓存体系
- Mybatis二级缓存实现详解
- Mybatis执行Mapper过程详解
- Mybatis插件原理及分页插件
- Spring集成Mybatis原理详解
这次,让我们跳出局部,看看Mybatis在设计和架构上,有哪些值得我们学习的地方。
注:本文中源码来自mybatis 3.4.x版本,地址github.com/mybatis/myb…
一 设计模式
1.1 建造者模式
MyBatis 大量使用建造者模式解决「复杂对象初始化」问题,比如 SqlSessionFactoryBuilder、XMLConfigBuilder、MapperBuilderAssistant 等。
以SqlSessionFactoryBuilder为例,在创建SqlSessionFactory前需要先解析主配置文件,这个过程非常繁琐。使用建造者模式:
- 分离「对象构建逻辑」和「对象使用逻辑」,让复杂对象创建流程清晰;
- 建造者可以分步骤校验配置正确性,避免无效对象产生;
- 多重载的 build 方法, 适配不同入参场景 。
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
// 简化代码:reader就是配置文件的读取流
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
}
}
1.2 工厂模式
工厂模式隐藏对象创建细节,上层无需关心「具体实现类」,只依赖接口。例如
SqlSessionFactory负责创建SqlSession,提供了多个重载实现。- Executor、StatementHandler、ResultSetHandler、ParameterHandler只能由
Configuration中的newExecutor等方法创建,根据配置选择不同实现类;同时应用自定义插件。
1.3 动态代理
MyBatis 核心的特性之一是「Mapper 接口无需实现类」,底层通过 JDK 动态代理,实现接口方法调用触发SQL执行。详见 MapperProxyFactory,缓存方法元数据,避免重复解析。
// 缓存mapper方法元数据,避免重复解析
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
此外,插件原理也是动态代理,定义Interceptor接口声明代理逻辑、代理对象创建等。使用户可以自定义插件实现。
1.4 模板方法
- 模板方法将「不变的通用逻辑」抽离到父类,「可变的差异化逻辑」交给子类实现;
- 避免子类重复编写通用代码(如缓存检查、参数校验),降低代码冗余;
- 父类控制流程,子类只关注核心逻辑,符合「开闭原则」。
BaseExecutor 实现了模板方法模式,将 Executor 的通用流程(如参数处理、SQL 执行、结果集处理)抽象为模板方法,具体子类(SimpleExecutor/BatchExecutor/ReuseExecutor)只需实现差异化逻辑。
// 模板方法,一级缓存使用逻辑
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
// ...,会调用doQuer()
}
// 由子类实现
protected abstract <E> List<E> doQuery(...)
1.5 装饰模式
用装饰模式替代继承,无需定义子类,就能给对象动态增加职责。
如通过CachingExecutor装饰,给BaseExecutor增加二级缓存能力。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// 对BaseExecutor子类进行装饰
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 省略...
}
如Cache接口体系,定义了很多装饰器,根据用户配置,实现功能特性自由组合。
1.6 策略模式
Executor接口可根据用户配置,运行时可切换SimpleExecutor、ReuseExecutor或BatchExecutor,实现不同的SQL执行策略。
RoutingStatementHandler 根据配置路由到不同的 StatementHandler实现。
1.7 注册中心
源码中大量使用 Registry 模式来管理可扩展组件, 可以统一初始化、统一查找、统一生命周期;例如:
- TypeHandlerRegistry
- MapperRegistry
- LanguageDriverRegistry
- CacheRegistry
二 架构思维
2.1 分层设计
MyBatis的核心分层非常清晰,每层只做一件事,符合「单一职责原则」:
- 各层职责:
- Mapper 层:用户接口,定义 SQL 操作;
- SqlSession 层:会话入口,封装 Executor 调用;
- Executor 层:执行器,处理缓存、事务、SQL 执行流程;
- StatementHandler 层:处理 SQL 拼接、Statement 创建;
- Parameter/ResultSetHandler 层:参数绑定、结果集映射;
- 架构思维:
- 分层降低耦合:修改结果集映射逻辑,不会影响 Executor 层;
- 每层依赖「接口」而非「实现」:比如 Executor 是接口,具体实现可替换;
- 分层便于测试:可单独测试 ParameterHandler 的参数绑定逻辑。
2.2 插件化设计
MyBatis 提供了插件扩展机制(Interceptor),允许开发者通过拦截器增强核心组件(Executor、StatementHandler、ParameterHandler、ResultSetHandler)的功能,实现如分页、日志、加密等。
- 核心设计:
- 定义
Interceptor接口,开发者实现intercept方法即可拦截目标方法; - 通过
@Intercepts注解指定拦截的类和方法,无需修改源码; - 拦截器链(InterceptorChain)通过动态代理层层包装目标对象,保证插件的有序执行;
- 定义
- 架构思维:
- 「开闭原则」的良好体现:框架核心功能固定,扩展功能通过插件实现,无需修改源码;
- 「责任链模式」:多个插件按顺序执行,每个插件只处理自己的逻辑,互不干扰;
- 扩展点设计要「最小化」:只开放核心组件的关键方法,避免过度暴露内部逻辑。
2.3 多级缓存
MyBatis 实现了「一级缓存(SqlSession 级别)+ 二级缓存(Mapper 级别)」的多级缓存:
- 一级缓存:BaseExecutor 中的
localCache(PerpetualCache),默认开启,SqlSession 关闭后失效; - 二级缓存:CachingExecutor 包装普通 Executor,缓存数据存入 Mapper 对应的 Cache 对象,跨 SqlSession 共享;
同时支持集成 Redis/Ehcache 等第三方缓存 。
2.4 面向接口编程
MyBatis 全程贯彻「依赖倒置原则」,完全面向接口编程:接口定义「做什么」,实现类定义「怎么做」,替换实现类不影响上层逻辑;
- 核心组件都是接口:
Executor、StatementHandler、ParameterHandler、ResultSetHandler、SqlSession等; - 上层代码只依赖接口:比如
SqlSession的selectList方法,底层调用的是Executor接口的query方法,无需关心具体是 SimpleExecutor 还是 BatchExecutor。
2.5 约定优于配置
MyBatis 大量使用约定来减少配置,通过约定可以显著降低配置量,提升开发体验。例如:
- Mapper 接口与 XML 文件同名同包;
- 方法名与 SQL ID 一致;
- 结果集字段与 JavaBean 属性自动映射;
StatementHandler接口默认使用PreparedStatementHandler
2.6 架构思维总结
MyBatis源码体现了简单而不简陋的设计哲学:
- 高内聚低耦合 - 模块职责清晰,依赖抽象
- 开闭原则 - 对扩展开放,对修改关闭
- 组合优于继承 - 装饰器、代理模式的应用
- 关注点分离 - SQL、映射、执行逻辑分离
- 性能优化 - 缓存、延迟加载、连接复用
上述技巧和思维不仅适用于框架开发,在日常业务开发中也能直接落地。
- 小型项目:学习其简洁的API设计
- 中型项目:借鉴其分层架构和模式应用
- 大型项目:参考其扩展机制和插件体系