[019][数据模块]MyBatis-Plus 拦截器扩展设计:基于函数式接口与 Spring 自动装配

简介: 本文介绍基于函数式接口`InnerInterceptorSupplier`与Spring `ObjectProvider`的MyBatis-Plus拦截器自动装配方案,支持按`@Order`声明式排序、延迟创建及模块化扩展,提升分页、乐观锁等能力的可插拔性与框架集成友好度。(239字)

[019][数据模块]MyBatis-Plus 拦截器扩展设计:基于函数式接口与 Spring 自动装配

本项目代码:https://gitee.com/yunjiao-source/tutorials4j/tree/master/framework

在基于 MyBatis-Plus 的数据访问层开发中,拦截器(Interceptor)是扩展分页、乐观锁、防全表误操作等能力的核心组件。通常我们会在配置类中手动创建 MybatisPlusInterceptor 并添加各个 InnerInterceptor。这种方式虽然直观,但当需要支持模块化、按顺序注册、允许外部定制时,就显得不够灵活。

本文介绍一种更优雅的设计:通过函数式接口 InnerInterceptorSupplier + Spring 的 ObjectProvider 机制,实现拦截器的自动收集与顺序装配。并结合 DataMybatisPlusConfiguration 的示例代码,分析其设计思想与实战用法。


一、背景:MyBatis-Plus 拦截器体系

MyBatis-Plus 提供了一套基于 Interceptor 的插件机制,其中 MybatisPlusInterceptor 是责任链的核心,它可以添加多个 InnerInterceptor(如分页、乐观锁、防全表攻击等)。典型配置如下:

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
   
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
    return interceptor;
}

这种写法的缺点:

  • 如果是框架或 starter 项目,用户想追加自定义拦截器,只能通过覆盖 MybatisPlusInterceptor Bean 的方式,容易丢失默认拦截器。
  • 拦截器的顺序不易被外部控制。
  • 不够“声明式”,缺乏扩展点。

二、核心接口:InnerInterceptorSupplier

@FunctionalInterface
public interface InnerInterceptorSupplier extends Supplier<InnerInterceptor> {
   
}

这是一个极其简洁的函数式接口,继承自 Supplier<InnerInterceptor>。它的作用不是直接提供拦截器,而是声明一个能够提供拦截器的工厂

在 Spring 容器中,任何实现了该接口的 Bean 都会被识别,并用于向 MybatisPlusInterceptor 贡献拦截器实例。这样做的好处:

  • 延迟创建Supplier 允许在真正需要时才 get() 拦截器。
  • 允许带参数的构造:比如分页拦截器需要 DbType,可以在 Supplier 实现中从配置中读取。
  • 支持 @Order 排序:多个 Supplier Bean 可以定义顺序,最终拦截器链的顺序就是这些 Supplier 的执行顺序。

三、自动配置类:DataMybatisPlusConfiguration

3.1 核心 Bean:mybatisPlusInterceptor

@Bean
MybatisPlusInterceptor mybatisPlusInterceptor(ObjectProvider<InnerInterceptorSupplier> innerInterceptorSuppliers) {
   
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    innerInterceptorSuppliers.orderedStream()
            .map(InnerInterceptorSupplier::get)
            .forEach(interceptor::addInnerInterceptor);
    return interceptor;
}

关键点解析:

  • ObjectProvider<InnerInterceptorSupplier>:Spring 提供的依赖注入方式,能获取指定类型的所有 Bean,并支持有序流(orderedStream())。
  • orderedStream() 会按照每个 Bean 上的 @Order 注解或 Ordered 接口进行排序。
  • 依次调用 get() 获取拦截器实例,添加到 MybatisPlusInterceptor 中。

这种设计使得拦截器的增加完全基于容器中的 Supplier Bean,而不是硬编码。外部模块只需要定义自己的 InnerInterceptorSupplier Bean 即可自动生效。

3.2 默认注册的三个内置拦截器

配置类通过 @Bean 方法提供了三个预置的 Supplier,并指定了顺序:

顺序 拦截器类型 作用
100 PaginationInnerInterceptor 自动分页,根据数据库方言生成分页 SQL
200 OptimisticLockerInnerInterceptor 乐观锁,配合 @Version 字段使用
300 BlockAttackInnerInterceptor 防全表更新/删除,防止无 where 条件的 SQL

代码示例:

@Bean
@Order(100)
InnerInterceptorSupplier paginationInnerInterceptorSupplier(DataProperties properties) {
   
    return () -> new PaginationInnerInterceptor(properties.getMybatisPlus().getDbType());
}

注意分页拦截器需要从配置类 DataProperties 中获取数据库类型,这正是使用了 Supplier 的延迟构造能力。


四、如何扩展自定义拦截器?

假设我们需要添加一个 SQL 性能监控拦截器(自定义实现 InnerInterceptor),步骤如下:

  1. 实现自定义拦截器(例如 PerformanceInnerInterceptor)。
  2. 在任意 @Configuration 类中声明一个 InnerInterceptorSupplier Bean,并指定 @Order(决定它在拦截器链中的位置)。
@Configuration
public class MyCustomInterceptorConfig {
   

    @Bean
    @Order(50)  // 将在分页拦截器(Order=100)之前执行
    public InnerInterceptorSupplier performanceInterceptorSupplier() {
   
        // 如果拦截器需要其他依赖,可以在这里从方法参数传入
        return PerformanceInnerInterceptor::new;
    }
}

启动 Spring Boot 应用后,DataMybatisPlusConfiguration 会自动收集该 Supplier 并将其拦截器添加到链中。

如果想替换某个默认拦截器(比如修改分页拦截器的参数),无需覆盖整个 MybatisPlusInterceptor,只需提供一个更高优先级@Order 更小)的同类型 Supplier 会怎么样?实际上不会替换,而是增加。若要真正的替换,需要小心设计:最好在配置类中通过 @ConditionalOnMissingBean 来让默认 Supplier 有条件注册。不过当前设计下,默认 Supplier 总是注册,所以用户如果想完全自定义分页逻辑,可以提供一个相同类型的拦截器(但顺序可能需要在默认之前或之后,取决于业务需要)。更标准的做法是让默认的核心拦截器也支持条件化,但本文不展开。


五、设计优势总结

设计点 传统方式 本文方式
扩展性 覆盖整个 MybatisPlusInterceptor Bean 只需添加一个 InnerInterceptorSupplier Bean
顺序控制 硬编码 addInnerInterceptor 顺序 @Order 注解声明式排序
延迟创建 Supplier 支持带参或条件化创建
框架集成友好 较差 符合 Spring 自动装配哲学,适合 Starter 开发

六、潜在注意点

  1. 顺序一致性问题orderedStream() 依赖 @Order,但不同 Supplier 之间若无明确顺序,行为可能不确定。建议所有自定义 Supplier 都显式标注 @Order
  2. 拦截器生效范围MybatisPlusInterceptor 对 MyBatis-Plus 的所有方法都生效,但部分拦截器(如分页)只对特定执行器有效,这是 MyBatis-Plus 自身行为。
  3. 重复添加风险:若多个 Supplier 返回同一类型的拦截器(比如两个分页拦截器),可能会产生冲突。通常默认配置已足够,扩展时应注意避免重复。
  4. 性能开销:Supplier 的调用仅在容器启动且装配拦截器时执行一次,运行时无额外开销。

七、总结

InnerInterceptorSupplier + DataMybatisPlusConfiguration 的设计展现了一种面向扩展开放,面向修改关闭的优雅实践。它充分利用了 Java 8 的 Supplier 函数式接口、Spring 的 ObjectProvider 有序注入以及 @Order 排序机制,使得 MyBatis-Plus 拦截器链的构建变得高度可插拔、可排序、可配置。

如果你的项目中也需要封装 MyBatis-Plus 基础设施,或者开发一个数据访问 Starter,这种模式值得借鉴。完整的代码已在 tutorials4j 框架中实现,读者可根据自身需求裁剪或增强。

目录
相关文章
|
3月前
|
存储 安全 Java
【Java基础】泛型:泛型擦除、通配符、上下界限定(附《思维导图》+《面试高频考点清单》)
本文系统梳理了Java泛型的核心知识体系,主要内容包括: 泛型概述:介绍了泛型的定义、本质和三大优势(类型安全、代码复用、可读性),以及泛型类、接口和方法的三种使用形式。 泛型擦除:深入解析了Java泛型实现的核心机制,包括擦除规则(无界类型擦除为Object,有界类型擦除为第一个边界类型)、擦除带来的问题(如无法使用instanceof、创建泛型数组等)及其解决方案。 泛型通配符:详细讲解了三种通配符类型(无界通配符、上界通配符和下界通配符)的语法、语义和使用场景。
|
3月前
|
人工智能 开发工具 开发者
终端里跑 3D 老鼠,桌面窗口成摆锤;AI 大佬新公司估值百亿起
上周技术圈的信息挺杂,但有几条线索值得放在一起看。 一边,AI 产品继续往具体工作流里走:Claude Code 开始支持 Agent View,OpenAI 把 Codex 带到移动端;另一边,开发者社区继续整活:有人给 Claude Code 做实体旋钮,有人做 Claude 用量桌面仪表盘,还有人把终端做成能显示 3D 老鼠的玩具。
420 1
终端里跑 3D 老鼠,桌面窗口成摆锤;AI 大佬新公司估值百亿起
|
3月前
|
人工智能 开发框架 自然语言处理
企业级Java AI开发框架核心模块:从资源整合到场景落地
JBoltAI是企业级Java AI应用开发框架,聚焦业务闭环落地,非工具堆砌。含五大模块:AI资源网关(统管20+模型)、智能数据治理(盘活私有数据)、企业本体语义模型(构建业务知识孪生)、零低代码应用开发、Agent数字员工平台,助力企业AI重塑与原生开发。(239字)
309 0
|
3月前
|
SQL 存储 缓存
【Java基础】核心关键字:final、static、volatile、synchronized、transient(附《思维导图》+《面试高频考点清单》)
本文系统解析Java五大核心关键字:final(不可变性)、static(类级共享)、volatile(轻量级可见性)、synchronized(重量级同步)与transient(序列化控制)。涵盖语义、使用场景、底层原理(内存屏障、Monitor、类加载机制等)、常见误区及高频面试要点。
【Java基础】核心关键字:final、static、volatile、synchronized、transient(附《思维导图》+《面试高频考点清单》)
|
3月前
|
SQL 关系型数据库 MySQL
批量操作进阶:百万行级数据导入的性能极限
本文分享百万行数据导入四大进阶技巧:分区表减少锁竞争、禁用索引加速写入、并行LOAD DATA榨干多核性能、金仓kdb_load专用工具再提速。实测100万行最快&lt;1秒,助你从分钟级跃升秒级!
|
3月前
|
存储 弹性计算 小程序
阿里云最便宜云服务器怎么选?38元/99元/199元机型性能全解析
阿里云推出38元/年、99元/年、199元/年三档高性价比云服务器,分别面向个人开发者、小微初创及中小企业。本文从配置、实测性能与适用场景三维度深度对比,助力大家轻松选择低成本上云!
803 4
|
2月前
|
人工智能 弹性计算 自然语言处理
2026年阿里云最新活动:云服务器抢购与特惠、云产品免费试用、AI产品活动
2026年,阿里云持续深化普惠战略,围绕云服务器、免费试用与AI产品三大板块推出系列优惠。云服务器方面,轻量应用服务器低至38元/年,ECS经济型e实例99元/年、u1实例199元/年,新购续费同价,活动有效期至2027年3月。免费试用覆盖160+云产品及多款解决方案,新客最高可领12个月试用权益。AI产品方面,阿里云百炼Token Plan提供多模型灵活订阅,按量达标最高返200元优惠券;HappyHorse视频生成模型限时8折;OpenClaw AI助理9.9元/月起即可部署。无论个人开发者还是企业用户,均可借助上述活动实现低成本上云与智能化升级。
|
3月前
|
算法 Java 程序员
程序员必备的十大技能(进阶版)之高阶数据结构与算法(二)
教程来源 http://xcfsr.cn/ 本节深度解析四大经典树形结构:红黑树(保障O(log n)性能,支撑Java/C++有序容器);B/B+树(数据库索引核心,优化磁盘I/O与范围查询);线段树(高效处理区间查询/更新,支持懒标记);前缀树(Trie,专精字符串匹配与自动补全)。附核心代码与时间复杂度分析。
|
3月前
|
程序员 开发工具 git
初级程序员必备的十大技能之规范编码与团队协作(三)
教程来源 http://qcycj.cn/ 本节系统阐述高效团队协作核心实践:从精准提问、高效会议、知识共享到冲突化解,并配套自动化工具链(Prettier/ESLint/Husky/Commitlint/GitHub Actions),全面提升研发协同质量与工程规范性。
|
3月前
|
设计模式 SQL Java
程序员必备的十大技能(进阶版)之精通主流框架与源码思想(二)
教程来源 http://qeext.cn/ 本文深入解析Spring框架中四大核心设计模式(工厂、模板方法、适配器、观察者)的实战应用,并详解Spring Boot自动配置原理:从@SpringBootApplication组合注解、spring.factories机制、条件化加载(@Conditional系列),到手写Starter实践,助你由源码理解走向约定优于配置的开发范式。

热门文章

最新文章