SpringBoot整合Mybatis自定义拦截器不起作用的处理方案
目录
- SpringBoot整合Mybatis自定义拦截器不起作用
- 1. 原始的读取mybatis-config.xml文件
- 2. 与SpringBoot容器整合
- 2.1 mybatis的自动装载
- 3. 在mybatis-config.xml配置又放入Spring容器
- SpringBoot 自定义Mybatis拦截器
- 第一种
- 第二种
- 第三种
SpringBoot整合Mybatis自定义拦截器不起作用 Mybatis插件生效的方式:
1. 原始的读取mybatis-config.xml文件
该方式和Spring无关,是通过反射的形式创建插件对象,此时会执行org.apache.ibatis.plugin.Interceptor#setProperties方法,以读取配置参数。
mybatis:mapper-locations: classpath*:/mapping/*.xmltype-aliases-package: com.tellme.pojo#读取全局配置的地址config-location: classpath:mybatis-config.xml
在resource目录下配置mybatis的全局配置:
2. 与SpringBoot容器整合
网上很多方案说:mybatis自定义拦截器上加上@Component注解便可以生效。但是我将自定义拦截器放入到Spring容器中,自定义拦截器却失效了。
然后找到了springboot配置多数据源后mybatis拦截器失效文章,说是自定义配置了数据源导致了拦截器失效。
2.1 mybatis的自动装载 源码位置:org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
@Configuration@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })@ConditionalOnBean(DataSource.class)@EnableConfigurationProperties(MybatisProperties.class)@AutoConfigureAfter(DataSourceAutoConfiguration.class)public class MybatisAutoConfiguration {private static Log log = LogFactory.getLog(MybatisAutoConfiguration.class); @Autowiredprivate MybatisProperties properties; //会依赖注入Spring容器中所有的mybatis的Interceptor拦截器@Autowired(required = false)private Interceptor[] interceptors; ...@Bean@ConditionalOnMissingBeanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setVfs(SpringBootVFS.class); if (StringUtils.hasText(this.properties.getConfigLocation())) {factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); }factory.setConfiguration(properties.getConfiguration()); //手动放入到了setPlugins方法中。if (!ObjectUtils.isEmpty(this.interceptors)) {factory.setPlugins(this.interceptors); }if (this.databaseIdProvider != null) {factory.setDatabaseIdProvider(this.databaseIdProvider); }if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); }if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); }if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {factory.setMapperLocations(this.properties.resolveMapperLocations()); }return factory.getObject(); }...}
上面源码中:自动注入了Interceptor[]数组(我们只需将mybatis的自定义拦截器对象放入到Spring容器中)。后续放入了sqlSessionFactory中。
但是项目中虽然自定义配置了sqlSessionFactory类,但却未设置factory.setPlugins(this.interceptors); 。导致即使将自定义拦截器放入到Spring容器,但却不生效。
解决方法,需要手动修改自定义的sqlSessionFactory类。
3. 在mybatis-config.xml配置又放入Spring容器
这种情况下,mybatis自定义拦截器会被执行两次。即在mybatis-config.xml配置的拦截器会通过反射的方式创建拦截器,放入Spring容器的拦截器也会被初始化。
源码位置:org.mybatis.spring.SqlSessionFactoryBean#buildSqlSessionFactory
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {Configuration configuration; ...读取属性中的plugins,即org.mybatis.spring.SqlSessionFactoryBean#setPlugins设置的。if (!isEmpty(this.plugins)) {for (Interceptor plugin: this.plugins) {configuration.addInterceptor(plugin); if (LOGGER.isDebugEnabled()) {LOGGER.debug("Registered plugin: '" + plugin + "'"); }}}...解析xml配置(通过反射创建拦截器对象)if (xmlConfigBuilder != null) {try {xmlConfigBuilder.parse(); if (LOGGER.isDebugEnabled()) {LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'"); }} catch(Exception ex) {throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex); } finally {ErrorContext.instance().reset(); }}return this.sqlSessionFactoryBuilder.build(configuration); }
最终会执行到:
private void pluginElement(XNode parent) throws Exception {if (parent != null) {for (XNode child: parent.getChildren()) {String interceptor = child.getStringAttribute("interceptor"); Properties properties = child.getChildrenAsProperties(); //反射创建mybatis的插件。Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance(); interceptorInstance.setProperties(properties); configuration.addInterceptor(interceptorInstance); }}}
【SpringBoot整合Mybatis自定义拦截器不起作用的处理方案】
SpringBoot 自定义Mybatis拦截器 开发过程中经常回需要对要执行的sql加以自定义处理,比如分页,计数等。通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。
@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class, RowBounds.class,ResultHandler.class})})public class MyPageInterceptor implements Interceptor {private static final Logger logger= LoggerFactory.getLogger(MyPageInterceptor.class); @Overridepublic Object intercept(Invocation invocation) throws Throwable {logger.warn(invocation.toString()); return invocation.proceed(); }@Overridepublic Object plugin(Object o) {return Plugin.wrap(o,this); }@Overridepublic void setProperties(Properties properties) {logger.warn(properties.toString()); }}
我的配置
mybatis:type-aliases-package: me.zingon.pagehelper.modelmapper-locations: classpath:mapper/*.xmlconfiguration:map-underscore-to-camel-case: truedefault-fetch-size: 100default-statement-timeout: 30
在springboot中要给mybatis加上这个拦截器,有三种方法,前两种方法在启动项目时不会自动调用自定义拦截器的setProperties方法。
第一种
直接给自定义拦截器添加一个@Component注解,当调用sql时结果如下,可以看到拦截器生效了,但是启动时候并没有自动调用setProperties方法。
文章图片
第二种
在配置类里添加拦截器,这种方法结果同上,也不会自动调用setProperties方法。
@Configurationpublic class MybatisConfig {@BeanConfigurationCustomizer mybatisConfigurationCustomizer() {return new ConfigurationCustomizer() {@Overridepublic void customize(org.apache.ibatis.session.Configuration configuration) {configuration.addInterceptor(new MyPageInterceptor()); }}; }}
第三种
这种方法就是跟以前的配置方法类似,在yml配置文件中指定mybatis的xml配置文件,注意config-location属性和configuration属性不能同时指定
mybatis:config-location: classpath:mybatis.xmltype-aliases-package: me.zingon.pagehelper.modelmapper-locations: classpath:mapper/*.xml
可以看到,在启动项目的时候setProperties被自动调用了
文章图片
前两种方法可以在初始化自定义拦截器的时候通过 @Value 注解直接初始化需要的参数。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- mybatisplus如何在xml的连表查询中使用queryWrapper
- mybatisplus|mybatisplus where QueryWrapper加括号嵌套查询方式
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- Spring|Spring Boot 整合 Activiti6.0.0
- springboot使用redis缓存