好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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方法。

第二种

在配置类里添加拦截器,这种方法结果同上,也不会自动调用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被自动调用了

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

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

原文链接:https://HdhCmsTestjianshu测试数据/p/5fddb7f67108

查看更多关于SpringBoot整合Mybatis自定义拦截器不起作用的处理方案的详细内容...

  阅读:104次