深入理解 MyBatis 拦截器:使用方式、拦截种类与实战应用

MyBatis 是 Java 领域广泛使用的 ORM 框架,而拦截器(Interceptor)机制是其强大的扩展能力之一。本文将带你系统了解 MyBatis 拦截器的使用方法、支持拦截的类型以及实际应用案例。


一、什么是 MyBatis 拦截器?

MyBatis 拦截器(Interceptor)是通过 Java 的插件机制(基于动态代理)实现的一种 增强功能。它允许开发者在 MyBatis 的核心执行流程中“插入”自定义逻辑,例如 SQL 执行前后、参数处理、结果映射等阶段。

MyBatis 使用 @Intercepts 注解标识拦截点,通过实现 org.apache.ibatis.plugin.Interceptor 接口来自定义插件。


二、拦截器的使用方式

2.1 实现 Interceptor 接口

@Intercepts({
    @Signature(
        type = StatementHandler.class,
        method = "prepare",
        args = {Connection.class, Integer.class}
    )
})
public class MyExampleInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 在这里编写增强逻辑,比如打印 SQL
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可以读取配置文件中的属性
    }
}

2.2 注册插件

可以在 MyBatis 配置文件中注册插件:

<plugins>
    <plugin interceptor="com.example.MyExampleInterceptor">
        <property name="someProperty" value="value"/>
    </plugin>
</plugins>

或者通过 Spring Boot 配置类注册:

@Configuration
@MapperScan("com.example.mapper")
public class MybatisConfig {
    @Bean
    public Interceptor myInterceptor() {
        return new MyExampleInterceptor();
    }
}

三、MyBatis 支持的拦截点

MyBatis 拦截器只能拦截以下四种接口中的方法:

接口可拦截方法说明
Executorupdatequery执行增删改查操作
ParameterHandlergetParameterObjectsetParameters参数处理
ResultSetHandlerhandleResultSets结果集处理
StatementHandlerprepareparameterizebatchupdatequerySQL 处理

**注意:**只能拦截这四个接口的方法,其他类无法拦截。


四、MyBatis 拦截器可以实现什么?

MyBatis 拦截器强大之处在于它的灵活性侵入性低,常见的应用包括:

4.1 分页逻辑处理(如 PageHelper)

拦截 StatementHandler.prepare 方法,修改 SQL 增加分页语句(如 LIMIT)。

BoundSql boundSql = statementHandler.getBoundSql();
String originalSql = boundSql.getSql();
String pageSql = originalSql + " LIMIT 0,10";
Field sqlField = boundSql.getClass().getDeclaredField("sql");
sqlField.setAccessible(true);
sqlField.set(boundSql, pageSql);

4.2 SQL 日志打印

拦截 StatementHandler.prepare,输出最终执行的 SQL 与参数。

BoundSql boundSql = statementHandler.getBoundSql();
System.out.println("SQL: " + boundSql.getSql());
System.out.println("Params: " + boundSql.getParameterObject());

4.3 多租户隔离

根据租户 ID 重写 SQL,在 WHERE 语句中追加租户过滤条件。

String tenantId = TenantContext.getTenantId();
String originalSql = boundSql.getSql();
String newSql = originalSql + " AND tenant_id = '" + tenantId + "'";
sqlField.set(boundSql, newSql);

4.4 数据权限控制

动态分析用户角色,改写 SQL 实现字段或行级权限隔离。

if (!UserContext.isAdmin()) {
    String originalSql = boundSql.getSql();
    String newSql = originalSql + " AND created_by = '" + UserContext.getUserId() + "'";
    sqlField.set(boundSql, newSql);
}

4.5 动态表名、分表分库

根据 ThreadLocal 中上下文信息修改表名。

String logicTable = "user";
String realTable = logicTable + "_" + ShardContext.getShardSuffix();
String newSql = originalSql.replaceAll("\\buser\\b", realTable);
sqlField.set(boundSql, newSql);

4.6 SQL 审计 / 灰度发布控制

记录操作行为日志,或根据不同灰度策略决定是否执行或修改 SQL。

AuditLogger.log(boundSql.getSql(), boundSql.getParameterObject());
if (GrayReleaseContext.isBlocked(boundSql.getSql())) {
    throw new RuntimeException("该 SQL 被灰度策略阻止执行");
}

五、小结

MyBatis 拦截器是一个轻量却强大的扩展机制,适用于各种中间件能力的实现,如分页、多租户、安全控制等。但要注意其侵入性操作可能引发潜在性能问题或逻辑异常,务必在使用时做好单元测试与边界验证。

如果你正在使用 MyBatis 进行复杂的查询处理或框架级能力封装,拦截器无疑是一个值得深入掌握的利器。


你在项目中用过拦截器做哪些扩展?欢迎评论区分享你的经验!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值