MyBatis拦截器不加载问题排查

2026-07-23 10:10:24 25 次阅读

MyBatis拦截器无法加载通常不是单一原因,而是配置链路中某一环节断裂导致插件未进入Executor执行链。实际项目中,这类问题往往表现为拦截器代码已编写完成,但SQL执行过程中完全没有触发任何拦截逻辑,日志也无输出。

排查的第一步需要确认拦截器是否被正确注册到MyBatis配置中。MyBatis插件机制依赖Configuration.addInterceptor进行注入,如果仅仅定义了Interceptor类但没有加入SqlSessionFactoryBean的plugins集合,拦截器不会生效。在Spring Boot环境中,常见错误是只定义了@Bean拦截器,却没有显式绑定到SqlSessionFactoryBean。

Java
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setPlugins(new Interceptor[]{new MyInterceptor()});
return factoryBean.getObject();
}

如果使用MyBatis-Plus或自动配置方式,需要检查是否被自动配置覆盖,尤其是自定义SqlSessionFactory后,Spring Boot默认配置将失效。

第二个关键点是拦截器注解是否正确。MyBatis拦截器必须使用@Intercepts和@Signature精确匹配目标方法,否则不会进入拦截链。例如:

Java
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})

常见问题是method或args不匹配,导致MyBatis无法识别该拦截点。尤其在MyBatis不同版本中Executor方法签名存在细微差异,版本升级后容易出现拦截失效。

第三个排查方向是Spring与MyBatis整合时的扫描路径问题。如果拦截器类未被Spring容器管理(未加@Component或未被@Configuration导入),即使代码存在也不会被注册到插件链中。可以通过启动日志确认bean是否被加载。

同时需要注意多数据源场景。在多个SqlSessionFactory配置下,拦截器可能只绑定到了其中一个工厂,而实际执行SQL使用的是另一个数据源对应的SqlSessionFactory。这种情况下表现为“部分SQL生效、部分不生效”。

日志级别也是关键辅助判断手段。将MyBatis日志调至DEBUG可以观察插件链加载情况:

logging.level.org.apache.ibatis=debug

如果插件生效,会在Configuration初始化阶段看到plugin注册信息,否则说明根本未进入插件链。

另一个容易忽略的问题是拦截器顺序。MyBatis插件采用责任链模式,如果多个插件存在,某些插件可能提前终止执行流程或包装对象失败,导致后续插件无法触发。特别是在引入分页插件PageHelper或MyBatis-Plus插件时,这类冲突较为常见。

还需检查是否使用了错误的SqlSession模板。如果项目中同时存在SqlSessionTemplate和原生SqlSession,实际执行路径不同也会导致拦截器表现异常。例如Spring事务管理下使用的代理SqlSession可能绕过部分手动配置路径。

在Spring Boot自动配置环境中,建议优先检查MyBatisAutoConfiguration是否被覆盖或排除。如果项目中自定义了MybatisConfigurationSupport或类似配置类,很容易导致自动插件注册逻辑失效。

缓存机制也可能造成误判。当二级缓存开启时,部分查询不会真正进入Executor执行,从而看似“拦截器未触发”。此时可以临时关闭缓存进行验证:

YAML
mybatis:
configuration:
cache-enabled: false

还有一种隐蔽情况是JDK动态代理与CGLIB代理混用导致的类型不一致问题,尤其在AOP与MyBatis结合使用时,代理层级变化可能使拦截器匹配失效。

综合排查思路可以按执行链路逐层验证:拦截器是否实例化 → 是否进入Spring容器 → 是否绑定SqlSessionFactory → 是否加入Configuration → 是否匹配@Signature → 是否进入Executor执行链 → 是否被缓存或代理绕过。

当问题复杂时,可以直接在Configuration初始化后打印插件列表:

Java
System.out.println(configuration.getInterceptors());

如果集合为空,说明注册失败;如果存在但未触发,则问题在匹配或执行路径。

MyBatis拦截器不加载问题本质是配置链路断点问题,而不是业务逻辑问题。只要逐层确认注册、匹配、执行三大环节,基本都能定位根因。