676 字
约 2 分钟
6
S08-J02 · 插件与拦截器链

适用读者:想写插件但不知道能拦什么的人。
前置:S08-B01。
覆盖旧文:899(72) + 空壳 1146 补写(E-S08-012)= 72 点。
上一篇:S08-J01 · 分页:PageHelper vs MP 分页插件
下一篇:S08-J03 · 缓存。


1. 一句话结论

MyBatis 插件只能拦四个对象的方法:Executor、StatementHandler、ParameterHandler、ResultSetHandler。拦别的地方不行——这是插件的全部疆域。

拦截点 能做什么
Executor 改 SQL、加缓存、分页(PageHelper/MP 分页都在这里)
StatementHandler 改 PreparedStatement、改 SQL 文本
ParameterHandler 改参数设置(如加密字段)
ResultSetHandler 改结果映射(如解密、脱敏)

2. 插件怎么写

@Intercepts(@Signature(type = Executor.class, method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class SqlLogPlugin implements Interceptor {
    public Object intercept(Invocation inv) throws Throwable {
        Object[] args = inv.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        System.out.println("[plugin] " + ms.getId());
        return inv.proceed();
    }
    public Object plugin(Object target) { return Plugin.wrap(target, this); }
}

三个要素:@Intercepts 声明拦哪里、intercept 写逻辑、plugin 用 Plugin.wrap 生成代理。


3. 多个插件的顺序

mybatis-plus:
  interceptor-order: ...

或 XML:

<plugins>
  <plugin interceptor="...A"/>
  <plugin interceptor="...B"/>
</plugins>

顺序规则:按配置顺序包裹(后配置的在外层)。分页插件通常放最后,保证它看到的是最终 SQL。


4. 插件的三个边界

边界 说明
拦不到 SqlSession 的 insert 等高层 API 那些最终仍走 Executor
拦不到 MyBatis 之外(如 JdbcTemplate) 插件只作用于 MyBatis
改 SQL 要同步改 count 否则分页总数不对(J01)

判据:"我想做的事发生在 SQL 执行前/后吗?" 是 → 插件;不是(如事务、鉴权)→ 拦截器/切面(S07-B03/B04)。


5. 五个误区

误区 真相
"插件什么都能拦" 只有四个对象
"插件很多不影响性能" 每个 SQL 都过一遍代理
"改 SQL 只改 list 就行" count 也要改
"插件能替代拦截器" 作用域不同(MyBatis vs MVC)
"顺序无所谓" 顺序影响最终 SQL 形态

6. 自检

  1. 四个拦截点分别能做什么?
  2. 分页插件拦在哪一层?
  3. 多个插件的执行顺序规则?
  4. 插件与 Spring 拦截器的分工?
  5. 改 SQL 为什么还要管 count?

7. 下一篇

S08-J03 · 缓存:一级/二级与失效

插件讲完,下一篇讲 MyBatis 最容易"看起来生效又好像没生效"的机制:两级缓存。


本篇属于系列《S08 · MyBatis 持久层》。旧文来源:A-899(空壳 1146 补写)。

S08-J02 · 插件与拦截器链
https://www.clxhxhhr.top/posts/5288/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。