欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-24 07:55:43
目录springboot整合mybatis自定义拦截器不起作用2. 与springboot容器整合3. 在mybatis-config.xml配置又放入spring容器springboot 自定义my...

springboot整合mybatis自定义拦截器不起作用

mybatis插件生效的方式:

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

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

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

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

<?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容器中,自定义拦截器却失效了。

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

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);
  @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

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拦截器

开发过程中经常回需要对要执行的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);
    @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());
    }
}

我的配置

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

@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属性不能同时指定

mybatis:
  config-location: classpath:mybatis.xml
  type-aliases-package: me.zingon.pagehelper.model
  mapper-locations: classpath:mapper/*.xml
<?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 注解直接初始化需要的参数。

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