gpt4 book ai didi

SpringBoot整合Mybatis自定义拦截器不起作用的处理方案

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 28 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章SpringBoot整合Mybatis自定义拦截器不起作用的处理方案由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

SpringBoot整合Mybatis自定义拦截器不起作用

Mybatis插件生效的方式:

1. 原始的读取mybatis-config.xml文件

该方式和Spring无关,是通过反射的形式创建插件对象,此时会执行org.apache.ibatis.plugin.Interceptor#setProperties方法,以读取配置参数.

?
1
2
3
4
5
mybatis:
   mapper-locations: classpath*:/mapping/*.xml
   type-aliases-package: com.tellme.pojo
   #读取全局配置的地址
   config-location: classpath:mybatis-config.xml

在resource目录下配置mybatis的全局配置:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<? xml version = "1.0" encoding = "UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
< configuration >
     < settings >
         < setting name = "cacheEnabled" value = "true" />
         < setting name = "lazyLoadingEnabled" value = "true" />
         < setting name = "multipleResultSetsEnabled" value = "true" />
         < setting name = "useColumnLabel" value = "true" />
         < setting name = "mapUnderscoreToCamelCase" value = "true" />
         < setting name = "useGeneratedKeys" value = "true" />
         < setting name = "defaultExecutorType" value = "SIMPLE" />
         < setting name = "defaultStatementTimeout" value = "25000" />
     </ settings >
     < typeAliases >
         < typeAlias alias = "Integer" type = "java.lang.Integer" />
         < typeAlias alias = "Long" type = "java.lang.Long" />
         < typeAlias alias = "HashMap" type = "java.util.HashMap" />
         < typeAlias alias = "LinkedHashMap" type = "java.util.LinkedHashMap" />
         < typeAlias alias = "ArrayList" type = "java.util.ArrayList" />
         < typeAlias alias = "LinkedList" type = "java.util.LinkedList" />
     </ typeAliases >
     <!--配置的插件名-->
     < plugins >
         < plugin interceptor = "com.xxx.yyy.plugins.PrintSqlInfoInterceptor" />
     </ plugins >
</ configuration >

2. 与SpringBoot容器整合

网上很多方案说:mybatis自定义拦截器上加上@Component注解便可以生效。但是我将自定义拦截器放入到Spring容器中,自定义拦截器却失效了.

然后找到了springboot配置多数据源后mybatis拦截器失效文章,说是自定义配置了数据源导致了拦截器失效.

2.1 mybatis的自动装载

源码位置:org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@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 );
   @Autowired
   private MybatisProperties properties;
    //会依赖注入Spring容器中所有的mybatis的Interceptor拦截器
   @Autowired (required = false )
   private Interceptor[] interceptors;
    ...
   @Bean
   @ConditionalOnMissingBean
   public 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 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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);
}

最终会执行到:

?
1
2
3
4
5
6
7
8
9
10
11
12
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拦截器

开发过程中经常回需要对要执行的sql加以自定义处理,比如分页,计数等。通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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 );
     @Override
     public Object intercept(Invocation invocation) throws Throwable {
         logger.warn(invocation.toString());
         return invocation.proceed();
     }
     @Override
     public Object plugin(Object o) {
         return Plugin.wrap(o, this );
     }
     @Override
     public void setProperties(Properties properties) {
         logger.warn(properties.toString());
     }
}

我的配置 。

?
1
2
3
4
5
6
7
mybatis:
   type-aliases- package : me.zingon.pagehelper.model
   mapper-locations: classpath:mapper/*.xml
   configuration:
     map-underscore-to-camel- case : true
     default -fetch-size: 100
     default -statement-timeout: 30

在springboot中要给mybatis加上这个拦截器,有三种方法,前两种方法在启动项目时不会自动调用自定义拦截器的setProperties方法.

第一种

直接给自定义拦截器添加一个@Component注解,当调用sql时结果如下,可以看到拦截器生效了,但是启动时候并没有自动调用setProperties方法.

SpringBoot整合Mybatis自定义拦截器不起作用的处理方案

第二种

在配置类里添加拦截器,这种方法结果同上,也不会自动调用setProperties方法.

?
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class MybatisConfig {
     @Bean
     ConfigurationCustomizer mybatisConfigurationCustomizer() {
         return new ConfigurationCustomizer() {
             @Override
             public void customize(org.apache.ibatis.session.Configuration configuration) {
                 configuration.addInterceptor( new MyPageInterceptor());
             }
         };
     }
}

第三种

这种方法就是跟以前的配置方法类似,在yml配置文件中指定mybatis的xml配置文件,注意config-location属性和configuration属性不能同时指定 。

?
1
2
3
4
mybatis:
   config-location: classpath:mybatis.xml
   type-aliases-package: me.zingon.pagehelper.model
   mapper-locations: classpath:mapper/*.xml
?
1
2
3
4
5
6
7
8
9
10
11
12
13
<? xml version = "1.0" encoding = "UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-config.dtd">
< configuration >
     < typeAliases >
         < package name = "me.zingon.pacargle.model" />
     </ typeAliases >
     < plugins >
         < plugin interceptor = "me.zingon.pagehelper.interceptor.MyPageInterceptor" >
             < property name = "dialect" value = "oracle" />
         </ plugin >
     </ plugins >
</ configuration >

可以看到,在启动项目的时候setProperties被自动调用了 。

SpringBoot整合Mybatis自定义拦截器不起作用的处理方案

前两种方法可以在初始化自定义拦截器的时候通过 @Value 注解直接初始化需要的参数.

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我.

原文链接:https://www.jianshu.com/p/5fddb7f67108 。

最后此篇关于SpringBoot整合Mybatis自定义拦截器不起作用的处理方案的文章就讲到这里了,如果你想了解更多关于SpringBoot整合Mybatis自定义拦截器不起作用的处理方案的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com