当前位置: 首页 > article >正文

MyBatis Interceptor执行顺序详解(plugin机制、责任链模式)

目录一、引言二、Interceptor的注册顺序2.1 配置文件注册mybatis-config.xml2.2 代码注册2.3 SpringBoot Order2.4 扩展 - PageHelper链最后即最先执行三、plugin机制与InterceptorChain3.1 InterceptorChain.pluginAll3.2 Interceptor.plugin3.3 Plugin.wrap(target, this)四、Configuration调用pluginAll生成Executor五、责任链模式的应用六、执行顺序重点先注册后执行七、示例代码八、结论一、引言在MyBatis中Interceptor拦截器是实现自定义功能的核心扩展点。通过插件机制开发者可以在SQL执行、参数处理、结果映射等关键流程中插入自定义逻辑。本文将深入介绍MyBatis中Interceptor的执行顺序重点关注Interceptor的注册顺序、plugin机制、Configuration如何调用pluginAll方法生成Executor以及责任链模式的应用并详细说明了“先注册后执行”的机制和Plugin.wrap底层实现。二、Interceptor的注册顺序MyBatis的Interceptor通常通过配置文件或代码注册到Configuration对象中。注册顺序非常重要因为它直接影响拦截器的执行顺序。2.1 配置文件注册mybatis-config.xmlpluginsplugininterceptorcom.example.MyInterceptor1/plugininterceptorcom.example.MyInterceptor2//plugins拦截器会按照配置文件中出现的顺序依次注册。2.2 代码注册configuration.addInterceptor(newMyInterceptor1());configuration.addInterceptor(newMyInterceptor2());同样拦截器会按照addInterceptor的调用顺序注册。2.3 SpringBoot Order如果你使用的是 mybatis-spring-boot-starter推荐方式可以通过Order注解明确指定顺序BeanOrder(1)publicInterceptorinterceptorA(){...}BeanOrder(2)publicInterceptorinterceptorB(){...}注册顺序说明Spring 会将所有类型为Interceptor的 Bean 注入到 MyBatis 的SqlSessionFactory中。默认情况下Spring 注入集合类型如 List时顺序为 Bean上Order注解声明的顺序。2.4 扩展 - PageHelper链最后即最先执行PageHelper通过实现InitializingBean.afterPropertiesSet方法强制将PageInterceptor放到拦截器列表的最后面即保证了PageInterceptor会最先被执行具体代码如下packagecom.github.pagehelper.autoconfigure;importcom.github.pagehelper.PageInterceptor;importorg.apache.ibatis.plugin.Interceptor;importorg.apache.ibatis.session.SqlSessionFactory;importorg.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;importorg.springframework.beans.factory.InitializingBean;importorg.springframework.boot.autoconfigure.AutoConfigureAfter;importorg.springframework.boot.autoconfigure.condition.ConditionalOnBean;importorg.springframework.boot.context.properties.EnableConfigurationProperties;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.Lazy;importjava.util.List;/** * 自定注入分页插件 * * author liuzh */ConfigurationConditionalOnBean(SqlSessionFactory.class)EnableConfigurationProperties({PageHelperProperties.class,PageHelperStandardProperties.class})AutoConfigureAfter(MybatisAutoConfiguration.class)//Import(PageHelperProperties.class)Lazy(false)publicclassPageHelperAutoConfigurationimplementsInitializingBean{privatefinalListSqlSessionFactorysqlSessionFactoryList;privatefinalPageHelperPropertiesproperties;publicPageHelperAutoConfiguration(ListSqlSessionFactorysqlSessionFactoryList,PageHelperStandardPropertiesstandardProperties){this.sqlSessionFactoryListsqlSessionFactoryList;this.propertiesstandardProperties.getProperties();}OverridepublicvoidafterPropertiesSet()throwsException{PageInterceptorinterceptornewPageInterceptor();interceptor.setProperties(this.properties);for(SqlSessionFactorysqlSessionFactory:sqlSessionFactoryList){org.apache.ibatis.session.ConfigurationconfigurationsqlSessionFactory.getConfiguration();if(!containsInterceptor(configuration,interceptor)){// 重点关注 configuration.addInterceptor(interceptor);}}}/** * 是否已经存在相同的拦截器 * * param configuration * param interceptor * return */privatebooleancontainsInterceptor(org.apache.ibatis.session.Configurationconfiguration,Interceptorinterceptor){try{// getInterceptors since 3.2.2returnconfiguration.getInterceptors().stream().anyMatch(config-interceptor.getClass().isAssignableFrom(config.getClass()));}catch(Exceptione){returnfalse;}}}三、plugin机制与InterceptorChain3.1 InterceptorChain.pluginAllMyBatis通过plugin机制实现拦截器的动态包装。核心类是InterceptorChain它维护一个Interceptor列表并负责将目标对象如Executor、StatementHandler等按顺序包装。InterceptorChain源码片段publicclassInterceptorChain{privatefinalListInterceptorinterceptorsnewArrayList();publicObjectpluginAll(Objecttarget){for(Interceptorinterceptor:interceptors){targetinterceptor.plugin(target);}returntarget;}}可以看到pluginAll方法会按照Interceptor注册顺序依次调用每个Interceptor的plugin方法将目标对象层层包装。3.2 Interceptor.pluginInterceptor接口publicinterfaceInterceptor{Objectintercept(Invocationinvocation)throwsThrowable;defaultObjectplugin(Objecttarget){returnPlugin.wrap(target,this);}defaultvoidsetProperties(Propertiesproperties){}}3.3 Plugin.wrap(target, this)MyBatis的plugin机制核心在于Plugin.wrap(target, this)方法。其底层实现主要依赖Java的动态代理JDK Proxy实现了对目标对象的拦截。主要流程判断目标对象是否需要拦截Plugin.wrap会根据Interceptor的Signature注解判断目标对象是否实现了需要拦截的接口如Executor、StatementHandler等。创建代理对象如果需要拦截Plugin.wrap会使用JDK动态代理生成一个代理对象。代理对象会在目标方法被调用时自动调用Interceptor的intercept方法。责任链传递多个Interceptor包装后代理对象会层层嵌套形成责任链。每个intercept方法内部通常会调用invocation.proceed()继续传递到下一个Interceptor或原始对象。源码简要publicclassPluginimplementsInvocationHandler{privateObjecttarget;privateInterceptorinterceptor;privateMapClass?,SetMethodsignatureMap;publicstaticObjectwrap(Objecttarget,Interceptorinterceptor){MapClass?,SetMethodsignatureMapgetSignatureMap(interceptor);Class?typetarget.getClass();// 判断是否需要拦截if(shouldIntercept(type,signatureMap)){returnProxy.newProxyInstance(type.getClassLoader(),getInterfaces(type,signatureMap),newPlugin(target,interceptor,signatureMap));}returntarget;}OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{// 判断是否拦截该方法if(shouldIntercept(method)){returninterceptor.intercept(newInvocation(target,method,args));}returnmethod.invoke(target,args);}}四、Configuration调用pluginAll生成Executor在MyBatis初始化时Configuration会创建Executor等核心组件并通过InterceptorChain的pluginAll方法进行包装典型流程以Executor为例ExecutorexecutornewSimpleExecutor();executorinterceptorChain.pluginAll(executor);这意味着Executor会被所有Interceptor按注册顺序依次包装形成一条“责任链”。五、责任链模式的应用MyBatis的plugin机制本质上是责任链模式Chain of Responsibility Pattern的应用。每个Interceptor都可以选择拦截或放行操作最终形成如下调用链Executor被第一个Interceptor包装返回一个代理对象。代理对象再被第二个Interceptor包装依次类推。执行SQL时调用链会从最外层Interceptor开始逐层向内传递直到原始Executor。这种模式带来的好处是拦截器可以灵活地插入、组合且执行顺序完全由注册顺序决定。六、执行顺序重点先注册后执行需要特别强调的是Interceptor的执行顺序遵循“先注册后执行”原则。注册时Configuration会将Interceptor按顺序添加到InterceptorChain的interceptors列表。包装时pluginAll方法会依次调用每个Interceptor的plugin方法将目标对象层层包裹。执行时调用链会从最外层最后注册的Interceptor开始逐层向内传递直到最先注册的Interceptor最后到原始对象。举例说明假设注册顺序为InterceptorA → InterceptorB → InterceptorC执行包装的顺序InterceptorChain.pluginAllInterceptorA.plugin → InterceptorB.plugin → InterceptorC.plugin最终目标对象的包装顺序为C包裹BB包裹AA包裹原始对象执行顺序为C → B → A → 原始对象七、示例代码假设有两个拦截器publicclassMyInterceptor1implementsInterceptor{publicObjectintercept(Invocationinvocation)throwsThrowable{System.out.println(MyInterceptor1 before);Objectresultinvocation.proceed();System.out.println(MyInterceptor1 after);returnresult;}}publicclassMyInterceptor2implementsInterceptor{publicObjectintercept(Invocationinvocation)throwsThrowable{System.out.println(MyInterceptor2 before);Objectresultinvocation.proceed();System.out.println(MyInterceptor2 after);returnresult;}}注册顺序为1→2执行顺序如下MyInterceptor2 before MyInterceptor1 before [原始Executor执行] MyInterceptor1 after MyInterceptor2 after八、结论Interceptor注册顺序决定执行顺序先注册的拦截器会被后执行责任链模式保证了拦截器的顺序性和可扩展性。Plugin.wrap(target, this)通过JDK动态代理实现拦截器包装只有目标对象实现了需要拦截的接口才会被代理拦截器通过intercept方法实现自定义逻辑。实际开发中务必关注拦截器的注册顺序合理设计拦截器的职责和顺序确保业务逻辑的正确性和可维护性。如需进一步了解可以参考MyBatis源码中的InterceptorChain和Plugin类实现以及项目中的拦截器注册代码。

相关文章:

MyBatis Interceptor执行顺序详解(plugin机制、责任链模式)

目录一、引言二、Interceptor的注册顺序2.1 配置文件注册(mybatis-config.xml)2.2 代码注册2.3 SpringBoot Order2.4 扩展 - PageHelper链最后(即最先执行)三、plugin机制与InterceptorChain3.1 InterceptorChain.pluginAll3.2 In…...

2026大专电子商务毕业生就业学数据分析的价值分析

电子商务与数据分析的行业趋势近年来电子商务行业数据化转型加速,企业普遍依赖数据分析优化运营、精准营销和供应链管理。2025年《中国电子商务报告》显示,超75%的电商企业将数据分析能力列为核心岗位要求,涵盖用户行为分析、销售预测等场景。…...

“AI+”引爆家电新一轮以旧换新,AWE上看AI家电“百花争艳”

3月12日,以“AI科技,慧享未来”为主题的中国家电及消费电子博览会(AWE)在上海启幕,长虹携全线AI家电矩阵亮相,从画质革新的RGB-Mini LED新品、AI人感空调、场景化的AI冰洗厨套系,再到AI智慧家居…...

收藏!2026大模型春招真相|200个真实JD拆解,后端/算法转岗必看(小白友好)

本人从后端开发传统算法双赛道转岗大模型,最近趁着金三银四春招,计划冲刺一波大模型相关岗位,但越准备越迷茫——大模型知识点繁杂且更新极快,个人精力有限,始终找不到重点,不知道该把时间花在哪些技能上才…...

Win11家庭版也能用组策略?3步教你手动安装gpedit.msc(附完整CMD代码)

解锁Windows 11家庭版的隐藏管理能力:手动部署组策略编辑器全指南 如果你正在使用Windows 11家庭版,可能早就发现了一个令人困惑的“缺失”——在运行对话框里输入gpedit.msc,系统会告诉你找不到这个文件。这并非你的系统出了问题&#xff0c…...

Blender新手必看:3种超简单模型环绕技巧(附详细步骤图)

Blender新手必看:3种超简单模型环绕技巧(附详细步骤图) 刚接触Blender,面对空白的3D视窗,是不是既兴奋又有点无从下手?尤其是当你需要让一堆物体,比如柱子、灯泡、甚至是科幻场景中的能量核心&a…...

一灯即千言:无线Andon系统如何重塑服装厂敏捷生产

在传统服装制造车间,问题的发现与解决往往依赖班组的巡视与工人的主动汇报,信息流如同穿梭的线头,容易纠缠、迟滞。一个微小的断针、一道色差的缝线、一次设备的异常停顿,都可能因为信息传递的“时间差”而演变为整批货品的延误。…...

Canoe中panel面板关联系统变量

背景:在SystemVariables中加了变量,但在Panel设计面板中未找到变量,be like 如下实际原因:在Environment中SystemVariables中新增数据后,未重新保存退出,导致此原因...

ChatGLM-6B多语言扩展:实现中英混合对话

ChatGLM-6B多语言扩展:实现中英混合对话 1. 引言 ChatGLM-6B作为一款优秀的开源对话模型,原生支持中英双语能力,但在实际使用中,很多开发者发现模型在处理中英混合对话时表现不够理想。比如当你问"帮我写一段Python代码实现…...

清研电子荣获维科杯·OFweek 2025年度动力电池材料创新技术奖

2026 年 3 月 12 日,维科杯・OFweek 2025锂电行业年度评选颁奖典礼在香港亚洲国际博览馆隆重举办。近 300 个参评项目历经专家评审、网络投票、行业编辑三轮严苛筛选,清研电子凭借动力电池材料领域“技术颠覆 产业落地 生态赋能” 的全方位优势&#x…...

立创开源:基于STM32F030的1kHz SPWM简易电池内阻测试仪设计与实现

手把手教你DIY一个电池内阻测试仪:从原理到实战 最近在折腾一些锂电池项目,发现电池内阻这个参数特别重要。内阻大了,电池放电时发热就厉害,容量也虚。市面上的专业内阻测试仪动辄上千,对咱们爱好者来说有点下不去手。…...

Stable-Diffusion-V1-5 辅助工业设计:生成产品概念草图与外观方案

Stable-Diffusion-V1-5 辅助工业设计:生成产品概念草图与外观方案 1. 引言 你有没有过这样的经历?面对一个全新的产品设计任务,脑子里想法很多,但要把它们画出来,却感觉无从下笔。一张白纸,一支笔&#x…...

Phi-3 Forest Laboratory API接口调用全指南:从鉴权到流式响应

Phi-3 Forest Laboratory API接口调用全指南:从鉴权到流式响应 你是不是也对那些能对话、能写代码的AI模型感到好奇,想自己动手调用一下试试?今天咱们就来聊聊怎么通过代码,跟一个叫Phi-3 Forest Laboratory的模型“说上话”。别…...

Realistic Vision V5.1本地化部署教程:纯离线、零网络依赖、宽屏交互界面搭建

Realistic Vision V5.1本地化部署教程:纯离线、零网络依赖、宽屏交互界面搭建 想在自己的电脑上体验媲美单反相机的人像摄影效果,但又担心复杂的云端配置和网络依赖?今天,我们就来手把手教你,如何将顶级的Realistic V…...

磁链三矢量

磁链三矢量在电机控制的世界里,磁链三矢量就像三位配合默契的舞者。想象你手里有个三相电机,三个相位互相纠缠的磁场总让你头疼。这时候不妨试试把ABC坐标系拍扁——没错,我说的就是把三相电流投影到二维平面的αβ坐标系变换。先来看段硬核代…...

SPI 2026 报告解读—服务企业的竞争,正在从“拼业务”变成“拼管理”

每年 SPI Research 发布的《Professional Services Maturity Benchmark》,对于专业服务企业管理都是极具参考价值的一份报告。这份报告已经持续做了 19 年,几乎可以说是全球专业服务企业最系统的经营数据研究之一。2026年的报告基于 509家专业服务企业的…...

DrissionPage实战:绕过滑块验证的精准定位与模拟操作(非深度学习方案)

1. 为什么选择非深度学习的滑块验证绕过方案 最近在做一个自动化项目时,遇到了滑块验证码这个拦路虎。刚开始我也考虑过用深度学习方案,但实测下来发现几个痛点:首先需要大量标注数据训练模型,其次识别准确率不稳定,最…...

Nano-Banana高效部署教程:Docker镜像开箱即用,无需conda环境配置

Nano-Banana高效部署教程:Docker镜像开箱即用,无需conda环境配置 你是不是也遇到过这种情况?看到网上那些酷炫的产品拆解图、爆炸图,自己也想动手做一个,结果发现要装一堆环境,什么Python、PyTorch、各种依…...

JAVA实习生问:为什么项目不用VO?

校大网原创,公众号首发给刚开始的线上实习生做代码评审,发现有一个同学在返回给前端的Response DO 对象 里面,又额外套了一层 VO 对象。我就问他:“为什么要多加一层?没有任何逻辑的增加,就好像是脱裤子放屁…...

如何通过监控指标保障数据库连接池稳定性?动态数据源连接池问题诊断与优化实践

如何通过监控指标保障数据库连接池稳定性?动态数据源连接池问题诊断与优化实践 【免费下载链接】dynamic-datasource dynamic datasource for springboot 多数据源 动态数据源 主从分离 读写分离 分布式事务 项目地址: https://gitcode.com/gh_mirrors/dy/dynami…...

2026年实测:国内如何直接使用Gemini?技术拆解与镜像站推荐

目前国内用户想直接体验Google Gemini的强大能力,最便捷的方式是通过聚合类镜像平台。经实测,RskAi(ai.rsk.cn) 是一个不错的选择,它实现了国内网络直接访问,并聚合了Gemini、GPT、Claude等主流模型&#x…...

【OpenClaw 保姆级教程】第五篇:前端可视化面板 + 日志监控 + 权限管理(最终篇)

哈喽宝子们!一路跟着教程走到现在,我们已经完成了 OpenClaw 本地部署、多渠道接入、自定义技能、服务器私有化、多技能联动、定时任务与 API 接口化,今天迎来系列最终篇—— 直接给你的 OpenClaw 装上可视化前端面板,搭配实时日志监控、多人权限控制,从命令行工具升级成一…...

告别VIP音频下载烦恼:xmly-downloader-qt5让你轻松获取喜马拉雅付费内容

告别VIP音频下载烦恼:xmly-downloader-qt5让你轻松获取喜马拉雅付费内容 【免费下载链接】xmly-downloader-qt5 喜马拉雅FM专辑下载器. 支持VIP与付费专辑. 使用GoQt5编写(Not Qt Binding). 项目地址: https://gitcode.com/gh_mirrors/xm/xmly-downloader-qt5 …...

ViT图像分类模型与CNN架构对比分析

ViT图像分类模型与CNN架构对比分析 1. 引言 图像分类技术发展到今天,已经涌现出多种不同的架构方案。传统的CNN(卷积神经网络)长期占据主导地位,而近年来兴起的ViT(Vision Transformer)模型则带来了全新的…...

MCP Sampling接口调用流拆解:从零到生产就绪仅需15分钟,附可复用的6层拦截校验模板

第一章:MCP Sampling接口调用流的全景认知与核心价值 MCP(Model Control Protocol)Sampling 接口是现代大模型服务编排中实现可控采样策略的关键契约层。它不仅封装了温度(temperature)、top-k、top-p、重复惩罚&#…...

FireRed-OCR Studio一文详解:Qwen3-VL多模态模型在文档理解中的突破

FireRed-OCR Studio一文详解:Qwen3-VL多模态模型在文档理解中的突破 1. 引言:当文档“开口说话” 想象一下这个场景:你手头有一份几十页的纸质报告,里面充满了复杂的表格、数学公式和精心排版的段落。老板要求你在两小时内把它变…...

4个维度提升论文效率:CQUThesis重庆大学LaTeX模板全攻略

4个维度提升论文效率:CQUThesis重庆大学LaTeX模板全攻略 【免费下载链接】CQUThesis :pencil: 重庆大学毕业论文LaTeX模板---LaTeX Thesis Template for Chongqing University 项目地址: https://gitcode.com/gh_mirrors/cq/CQUThesis CQUThesis作为重庆大学…...

3步解决Navicat密码遗忘难题:开源解密工具全流程使用指南

3步解决Navicat密码遗忘难题:开源解密工具全流程使用指南 【免费下载链接】navicat_password_decrypt 忘记navicat密码时,此工具可以帮您查看密码 项目地址: https://gitcode.com/gh_mirrors/na/navicat_password_decrypt 数据库管理工作中,忘记N…...

OllyDBG逆向分析入门:手把手教你调试微信程序(附常用快捷键大全)

OllyDBG实战指南:从零开始掌握Windows程序调试艺术 最近有不少朋友在后台留言,问我怎么开始学习逆向分析。说实话,这个领域确实有点门槛,但只要你掌握了正确的工具和方法,其实并没有想象中那么难。今天我就以大家最熟悉…...

新手必看:PDF-Parser-1.0快速入门指南,开箱即用的文档解析神器

新手必看:PDF-Parser-1.0快速入门指南,开箱即用的文档解析神器 你是不是经常被PDF文档搞得头疼?想从一份技术报告里复制个表格,结果格式全乱了;想提取白皮书里的关键数据,却要手动一页页翻找;或…...