主题
MyBatis 架构与插件机制
一、整体架构(三层)
| 层 | 职责 |
|---|---|
| 接口层 | 对外 API:SqlSession / Mapper 接口 |
| 数据处理层 | SQL 查找、解析、执行、结果映射(四大组件所在层) |
| 框架支撑层 | 连接管理、事务、配置加载、缓存 |
二、四大核心组件(插件拦截点)
MyBatis 对以下四个对象提供了拦截/扩展机制,插件本质就是拦截器,增强靠动态代理实现——四大对象在创建时返回的其实都是被层层代理后的对象:
| 组件 | 职责 | 可拦截方法 |
|---|---|---|
Executor | 增删改查、事务提交/回滚 | update / query / commit / rollback |
StatementHandler | SQL 语法构建 | prepare / parameterize / batch / query |
ParameterHandler | 参数处理 | getParameterObject / setParameters |
ResultSetHandler | 结果集处理 | handleResultSets / handleOutputParameters |
三、插件原理
- 四大对象创建时不直接返回,而是经过
interceptorChain.pluginAll(target); - 取出所有
Interceptor,逐个调用interceptor.plugin(target),返回被包装(代理)后的对象; - 代理拦截到四大对象的每次调用,织入增强逻辑。
interceptorChain在 MyBatis 初始化时创建,持有全部拦截器;- 最终
target是"重重代理"后的对象。
四、自定义插件(示例)
java
@Intercepts({
@Signature(type = StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class})
})
public class MyPlugin implements Interceptor {
@Override public Object intercept(Invocation invocation) throws Throwable {
System.out.println("对方法进行了增强");
return invocation.proceed(); // 原方法执行
}
@Override public Object plugin(Object target) {
return Plugin.wrap(target, this); // 生成代理,纳入拦截器链
}
@Override public void setProperties(Properties properties) {
System.out.println("配置参数:" + properties);
}
}XML 注册(注意 <plugins> 标签顺序):
xml
<plugins>
<plugin interceptor="com.wy.plugin.MyPlugin">
<property name="name" value="tom"/>
</plugin>
</plugins>方法执行顺序:setProperties() → plugin() → intercept()。
常见误解
- "插件能拦截任意类" —— 错,只能拦截四大组件公布的指定方法。
- "plugin() 里要自己写 JDK/CGLIB 代理" —— 错,调
Plugin.wrap(target, this)即可(MyBatis 已封装)。 - "四大对象是原始对象" —— 错,经过拦截器链后它们都是代理对象。
关联
- 上游:Mybatis架构层次 · MyBatis插件
- 同域:MyBatis缓存机制(缓存装饰器链与插件拦截器链思路类似,都是"层层包装")· 手写持久层框架(MyBatis原理铺垫)
- 域地图:Java后端