[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 框架中实现,读者可根据自身需求裁剪或增强。

目录
相关文章
|
15小时前
|
缓存 算法 搜索推荐
程序员必备的十大技能(进阶版)之高阶数据结构与算法(四)
教程来源 http://qcycj.cn/ 本节介绍海量数据与字符串匹配核心算法:布隆过滤器(高效判存、允许误报)、倒排索引(支撑搜索引擎的词→文档映射)、KMP(线性单模匹配)及AC自动机(O(n)多模匹配)。兼顾原理、代码实现与典型场景,适用于缓存穿透防护、URL去重、全文检索与敏感词识别等工业级应用。
|
10小时前
|
存储 安全 Java
【Java基础】泛型:泛型擦除、通配符、上下界限定(附《思维导图》+《面试高频考点清单》)
本文系统梳理了Java泛型的核心知识体系,主要内容包括: 泛型概述:介绍了泛型的定义、本质和三大优势(类型安全、代码复用、可读性),以及泛型类、接口和方法的三种使用形式。 泛型擦除:深入解析了Java泛型实现的核心机制,包括擦除规则(无界类型擦除为Object,有界类型擦除为第一个边界类型)、擦除带来的问题(如无法使用instanceof、创建泛型数组等)及其解决方案。 泛型通配符:详细讲解了三种通配符类型(无界通配符、上界通配符和下界通配符)的语法、语义和使用场景。
|
13小时前
|
人工智能 开发工具 开发者
终端里跑 3D 老鼠,桌面窗口成摆锤;AI 大佬新公司估值百亿起
上周技术圈的信息挺杂,但有几条线索值得放在一起看。 一边,AI 产品继续往具体工作流里走:Claude Code 开始支持 Agent View,OpenAI 把 Codex 带到移动端;另一边,开发者社区继续整活:有人给 Claude Code 做实体旋钮,有人做 Claude 用量桌面仪表盘,还有人把终端做成能显示 3D 老鼠的玩具。
终端里跑 3D 老鼠,桌面窗口成摆锤;AI 大佬新公司估值百亿起
|
14小时前
|
人工智能 开发框架 自然语言处理
企业级Java AI开发框架核心模块:从资源整合到场景落地
JBoltAI是企业级Java AI应用开发框架,聚焦业务闭环落地,非工具堆砌。含五大模块:AI资源网关(统管20+模型)、智能数据治理(盘活私有数据)、企业本体语义模型(构建业务知识孪生)、零低代码应用开发、Agent数字员工平台,助力企业AI重塑与原生开发。(239字)
|
15小时前
|
算法 程序员 调度
程序员必备的十大技能(进阶版)之高阶数据结构与算法(五)
教程来源 http://oplhc.cn/ 本节系统讲解动态规划与贪心策略:DP以状态定义、转移方程、初始条件和遍历顺序为核心,涵盖LCS、0-1/完全/多重背包;贪心需严格证明(如交换论证),典型应用包括区间调度、哈夫曼编码。同时对比分治、回溯、分支限界与随机化算法,构建完整算法设计认知体系。
|
14小时前
|
存储 弹性计算 安全
阿里云99元和199元云服务器怎么买更划算?最新专属组合套餐配置与价格参考
阿里云99元(e实例,2核2G/3M/40G)和199元(u1实例,2核4G/5M/80G)云服务器是个人开发者与中小企业的高性价比之选,活动截止2027年3月31日,新购续费同价。最优选购策略是搭配组合套餐:加99元可解锁弹性数据库(ECS+RDS 198元起)或高效存储(ECS+OSS 217.99元起);建站用户可选域名+ECS+建站礼包(460元起)或域名+ECS+SSL证书(525元起),建议通过选购组合套餐形式,一站式采购,实现省心降本。
|
14小时前
|
SQL 关系型数据库 MySQL
批量操作进阶:百万行级数据导入的性能极限
本文分享百万行数据导入四大进阶技巧:分区表减少锁竞争、禁用索引加速写入、并行LOAD DATA榨干多核性能、金仓kdb_load专用工具再提速。实测100万行最快&lt;1秒,助你从分钟级跃升秒级!
|
14天前
|
缓存 NoSQL 算法
【Redis】Redis——过期键删除策略、内存淘汰8种策略、LRU/LFU实现
Redis过期删除与内存淘汰是两大核心内存管理机制:前者按TTL自动清理失效键(惰性+定期组合),后者在`maxmemory`超限时主动淘汰键(8种策略,含LRU/LFU近似实现)。二者目标、触发条件与作用范围截然不同,需精准区分与配置。
|
16天前
|
缓存 安全 搜索推荐
[004][缓存模块]Caffeine缓存自定义:构建灵活的Spring Boot缓存管理器
本文介绍Spring Boot中Caffeine缓存的灵活定制方案:通过自定义`FlexibleCaffeineCacheManager`,支持按缓存名(如users/products)独立配置过期策略、容量等参数,兼顾全局默认与个性化需求;结合线程安全创建器、属性合并机制及无缝Spring集成,实现高性能、易扩展、零侵入的本地缓存管理。(239字)
70 2
|
22天前
|
人工智能 API
HappyHorse 1.0已登陆阿里云百炼,HappyHorse视频生成定价720P 0.9元/秒、1080P 1.6元/秒,API服务可通过阿里云百炼直接调用。
阿里云HappyHorse 1.0视频生成模型正式登陆百炼平台,在百炼平台:https://t.aliyun.com/U/fPVHqY 申请使用,HappyHorse支持文生视频、图生视频及音视频联合生成;具备1080P超分、15秒多镜头叙事能力,画面质感、人物真实感与可控性突出。720P/1080P生成单价分别为0.9元/秒、1.6元/秒,API直调可用。
324 1