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

然后找到了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);
  @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方法。

第二种

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

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

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

(0)

相关推荐

  • springboot整合mybatis中的问题及出现的一些问题小结

    1.springboot整合mybatis mapper注入时显示could not autowire,如果强行写(value  = false ),可能会报NullPointException异常 解决方案: dao层加注解@Component(value = "首字母小写的接口名如UserMapper->userMapper") dao层还可以加注解@Mapper 2.The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecogni

  • SpringBoot整合mybatis常见问题(小结)

    Spring中常见问题 1.NoSuchBeanDefinitionException 2.'..Service' that could not be found service找不到 3.port 80 was already in use 端口号被占用 4.TemplateInputException 模板解析异常或找不到模板 1.检查模板所在的目录是否与配置的前缀目录相同 2.检查返回的模板是否存在,返回值类型是否一致 3.检查配置前缀时是否以"/"斜杠结尾 4.控制层的url与

  • 解决SpringBoot整合Mybatis扫描不到Mapper的问题

    闲来无事,想学学springboot,开始搭建一个项目,但是一直显示mapper扫描不到的错误: "Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController': Unsa

  • springboot整合mybatis分页拦截器的问题小结

    简介 又到了吹水时间,是这样的,今天开发时想将自己写好的代码拿来优化,因为不想在开发服弄,怕搞坏了到时候GIT到生产服一大堆问题,然后把它分离到我轮子(工具)项目上,最后运行后发现我获取List的时候很卡至少10秒,我惊了平时也就我的正常版本是800ms左右(不要看它很久,因为数据量很大,也很正常.),前提是我也知道很慢,就等的确需要优化时,我在放出我优化的plus版本,回到10秒哪里,最开始我刚刚接到这个app项目时,在我用 PageHelper.startPage(page, num);(分

  • 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文件 该方式和

  • Mybatis自定义拦截器和插件开发详解

    前言 在Spring中我们经常会使用到拦截器,在登录验证.日志记录.性能监控等场景中,通过使用拦截器允许我们在不改动业务代码的情况下,执行拦截器的方法来增强现有的逻辑.在mybatis中,同样也有这样的业务场景,有时候需要我们在不侵入原有业务代码的情况下拦截sql,执行特定的某些逻辑.那么这个过程应该怎么实现呢,同样,在mybatis中也为开发者预留了拦截器接口,通过实现自定义拦截器这一功能,可以实现我们自己的插件,允许用户在不改动mybatis的原有逻辑的条件下,实现自己的逻辑扩展. 本文将按

  • 在springboot中如何给mybatis加拦截器

    目录 1.实现Interceptor接口,并添加拦截注解 @Intercepts 1.在mybatis中可被拦截的类型有四种(按照拦截顺序) 2.各个参数的含义 2.在配置文件中添加拦截器 (1)第一种 (2)第二种 (3)第三种 拦截器的作用就是我们可以拦截某些方法的调用,在目标方法前后加上我们自己逻辑 Mybatis拦截器设计的一个初衷是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑. mybatis 自定义拦截器 1.实现Interceptor 接口,并添加拦截注

  • 解决SpringBoot自定义拦截器和跨域配置冲突的问题

    目录 SpringBoot自定义拦截器和跨域配置冲突 技术栈 问题引出 原代码 新代码 SpringBoot 拦截器和addCorsMappings冲突 SpringBoot自定义拦截器和跨域配置冲突 技术栈 vue-cli3,springboot 2.3.2.RELEASE 问题引出 在做毕业设计过程中用到了自定义拦截器验证登录.同时在springboot配置类中设置了跨域问题,出现跨域失败的情况. 原代码 @Configuration public class WebConfig exten

  • 解决mybatis分页插件PageHelper导致自定义拦截器失效

    目录 问题背景 mybatis拦截器使用 使用方法: 注解参数介绍: setProperties方法 bug内容: 自定义拦截器部分代码 PageInterceptor源码: 解决方法: 解决方案一 调整执行顺序 解决方案二 修改拦截器注解定义 问题背景 在最近的项目开发中遇到一个需求 需要对mysql做一些慢查询.大结果集等异常指标进行收集监控,从运维角度并没有对mysql进行统一的指标搜集,所以需要通过代码层面对指标进行收集,我采用的方法是通过mybatis的Interceptor拦截器进行

  • SpringBoot配置自定义拦截器实现过程详解

    目录 1. HttpServletRequest包装类 2. 使用Filter将request传递下去 3. 添加拦截器 4. 全局异常处理器 5. 配置拦截器 1. HttpServletRequest包装类 因为HttpServletRequest只能读取一次,所以需要对request进行包装,变成可重复读的request. package net.lesscoding.interceptor; import javax.servlet.ReadListener; import javax.

  • springboot自定义拦截器简单使用及举例

    目录 1. 自定义拦截器 2. 拦截器登录验证的小demo 2.1 配置pom.xml 2.2 创建User的bean组件 2.3 创建需要的表单页面以及登录成功的页面 2.4 编写controller映射关系 2.5 自定义拦截器类,实现intercepetor接口 2.6注册添加拦截器,自定义springboot配置类 2.7 运行测试 总结 1. 自定义拦截器 在springboot中,使用自定义拦截器,只需要将类实现HandlerIntercepter接口(与原生的filter也基本差不

  • SpringBoot登录用户权限拦截器

    1. 创建自定义拦截器类并实现 HandlerInterceptor 接口 package com.xgf.online_mall.interceptor; import com.xgf.online_mall.system.domain.User; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.Ha

随机推荐