关于MyBatis拦截器失效问题的解决(多数据源、分页插件)

这篇具有很好参考价值的文章主要介绍了关于MyBatis拦截器失效问题的解决(多数据源、分页插件)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

最近做了一个备份被delete语句删除的数据的小插件,是用MyBatis的拦截器去做的。

但是发现在一个项目中会失效,没有去备份删除的数据,查看日志发现请求并没有进入到拦截器中,换句话说就是拦截器失效了。

百度了一下(哎,百度)发现说的最多的就是分页插件导致的,但是我这个项目中并没有用到分页插件,所以应该不是这个问题,看来只能自己找了。

找问题

拦截器失效了,第一反应肯定要去找找拦截器执行的方法,在InterceptorChain里面的pluginAll:

public class InterceptorChain {

  private final List<Interceptor> interceptors = new ArrayList<>();

  // 拦截器执行的方法
  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }

  public List<Interceptor> getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }

}

这里的pluginAll方法会循环遍历interceptors,去调用plugin方法,plugin方法会返回动态代理之后的对象。

Plugin实现了InvocationHandler,在invoke方法中,去调用了interceptor的intercept方法

public class Plugin implements InvocationHandler {

  private final Object target;
  private final Interceptor interceptor;
  private final Map<Class<?>, Set<Method>> signatureMap;

  private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
    this.target = target;
    this.interceptor = interceptor;
    this.signatureMap = signatureMap;
  }

  public static Object wrap(Object target, Interceptor interceptor) {
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      // 返回动态代理对象
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      if (methods != null && methods.contains(method)) {
      	// 调用intercept方法,返回结果
        return interceptor.intercept(new Invocation(target, method, args));
      }
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }

我在InterceptorChain的pluginAll方法里打了个断点,发现List<Interceptor> interceptors中并没有我的那个拦截器,只有一个MPJInterceptor mybatis-plus的拦截器,那估计就是拦截器没有加到这个list中,但是SpringBoot使用这个拦截器很简单,连配置都没有,不应该没有扫到,而且其他项目中都是正常的,扫描配置应该没问题,可能是添加的地方有问题。

interceptors是私有的,只需要看addInterceptor方法的调用就行了(mybatis的源码看起来还是很友好的),中间的调用就不赘述了,最上层是在MybatisPlusAutoConfiguration中的sqlSessionFactory方法里:

 	@Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        // TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean
        MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }
        applyConfiguration(factory);
        if (this.properties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(this.properties.getConfigurationProperties());
        }
        // 这里,是添加拦截器的
        // 至于interceptors是怎么来的,那就是另外一个故事了
        if (!ObjectUtils.isEmpty(this.interceptors)) {
            factory.setPlugins(this.interceptors);
        }
        if (this.databaseIdProvider != null) {
            factory.setDatabaseIdProvider(this.databaseIdProvider);
        }

@Bean说明它是一个bean的定义方法,重点是@ConditionalOnMissingBean:容器里没有SqlSessionFactory的bean时,才会去走这个方法生成SqlSessionFactory的bean。

然后调试了一下,发现初始化的时候并没有走到这个方法里去,说明之前就有SqlSessionFactory的bean了。

然后发现配置了多数据源。。。配置多数据源的时候,配置了SqlSessionFactory的bean,还是多个,这样就不会走上面的初始化流程了,所以也就不会添加自定义的拦截器。

但是MPJInterceptor拦截器是怎么添加进去的?

然后我找到了InterceptorConfig:

/**
 * 拦截器配置类 如果配置了分页插件,可能会使拦截器失效
 * 此类的作用就是校验拦截器顺序,保证连表插件在其他拦截器之前执行
 *
 * @author yulichang
 */
@SuppressWarnings("SpringJavaAutowiredMembersInspection")
public class InterceptorConfig implements ApplicationListener<ApplicationReadyEvent> {

    private static final Log logger = LogFactory.getLog(InterceptorConfig.class);

    @Autowired(required = false)
    private List<SqlSessionFactory> sqlSessionFactoryList;
    @Autowired(required = false)
    private MPJInterceptor mpjInterceptor;
    @Autowired(required = false)
    private ISqlInjector iSqlInjector;

    @Override
    @SuppressWarnings("unchecked")
    public void onApplicationEvent(ApplicationReadyEvent event) {
        if (CollectionUtils.isNotEmpty(sqlSessionFactoryList) && Objects.nonNull(mpjInterceptor)) {
            try {
                for (SqlSessionFactory factory : sqlSessionFactoryList) {
                    Field interceptorChain = Configuration.class.getDeclaredField("interceptorChain");
                    interceptorChain.setAccessible(true);
                    InterceptorChain chain = (InterceptorChain) interceptorChain.get(factory.getConfiguration());
                    Field interceptors = InterceptorChain.class.getDeclaredField("interceptors");
                    interceptors.setAccessible(true);
                    List<Interceptor> list = (List<Interceptor>) interceptors.get(chain);
                    if (CollectionUtils.isNotEmpty(list)) {
                        if (list.get(list.size() - 1) != mpjInterceptor) {
                            list.removeIf(i -> i == mpjInterceptor);
                            list.add(mpjInterceptor);
                        }
                    } else {
                        list.add(mpjInterceptor);
                    }
                }
            } catch (Exception ignored) {
                throw new MPJException("mpjInterceptor exception");
            }
        }
        if (iSqlInjector != null && !(iSqlInjector instanceof MPJSqlInjector)) {
            logger.error("sql注入器未继承 MPJSqlInjector -> " + iSqlInjector.getClass());
        }
    }
}

原来是手动塞进去的,难怪,顺便解决了分页插件的问题。

到这里,问题的解决方法是很明显了吧。。。文章来源地址https://www.toymoban.com/news/detail-621541.html

到了这里,关于关于MyBatis拦截器失效问题的解决(多数据源、分页插件)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 自定义MyBatis拦截器更改表名

    by emanjusaka from ​ https://www.emanjusaka.top/2023/10/mybatis-interceptor-update-tableName 彼岸花开可奈何 本文欢迎分享与聚合,全文转载请留下原文地址。 自定义MyBatis拦截器可以在方法执行前后插入自己的逻辑,这非常有利于扩展和定制 MyBatis 的功能。本篇文章实现自定义一个拦截器去改

    2024年02月08日
    浏览(42)
  • MyBatis Plus 拦截器实现数据权限控制

    上篇文章介绍的MyBatis Plus 插件实际上就是用拦截器实现的,MyBatis Plus拦截器对MyBatis的拦截器进行了包装处理,操作起来更加方便 2.1、InnerInterceptor MyBatis Plus提供的InnerInterceptor接口提供了如下方法,主要包括:在查询之前执行,在更新之前执行,在SQL准备之前执行 2.2、编写简

    2024年01月17日
    浏览(39)
  • SpringMVC中的拦截器不生效的问题解决以及衍生出的WebMvcConfigurationSupport继承问题思考

    过滤器代码(被Spring扫描并管理): 过滤器配置代码: 按理说我们发出请求 localhost/stu 之后,应该可以看到过滤器的效果,但是失效了。 网上的说法众说纷纭: 没加@Component或者@Configuration注解 @ComponentScan没扫描到 路径配置错了 以上三种说法一一排除之后,我发现一个博客提

    2024年02月01日
    浏览(36)
  • Mybatis拦截器注解@Intercepts与@Signature注解属性说明

    可能有些新手使用mybatis拦截器的时候可能没太懂@Signature注解中type,method,args的用法 首先mybatis拦截器可以拦截如下4中类型 Executor sql的内部执行器 ParameterHandler 拦截参数的处理 StatementHandler 拦截sql的构建 ResultSetHandler 拦截结果的处理 type:就是指定拦截器类型(ParameterHandl

    2024年02月05日
    浏览(43)
  • 利用Mybatis拦截器实现自定义的ID增长器

    原生的Mybatis框架是没有ID自增器,但例如国产的Mybatis Plus却是支持,不过,Mybatis Plus却是缺少了自定属性的填充;例如:我们需要自定义填充一些属性,updateDate、createDate等,这时Mybatis Plus自带的ID自增器就无法满足需求;这种时候我们就需要自定义的ID增加器,可以自定义

    2024年02月19日
    浏览(43)
  • 基于Mybatis-Plus拦截器实现MySQL数据加解密

    用户的一些敏感数据,例如手机号、邮箱、身份证等信息,在数据库以明文存储时会存在数据泄露的风险,因此需要进行加密, 但存储数据再被取出时,需要进行解密,因此加密算法需要使用对称加密算法。 常用的对称加密算法有AES、DES、RC、BASE64等等,各算法的区别与优劣

    2024年02月16日
    浏览(38)
  • MyBatis拦截器-打印出真正执行的sql语句和执行结果

    目录 广而告之 背景 先看成品 实现步骤 第一步,实现Interceptor接口 ​编辑 第二步,给拦截器指定要拦截的方法签名 第三步,实现拦截器的intercept方法。 第四步,在mybatis-config.xml里配置上这个拦截器插件 第五步,禁用mybatis打印日志 给大家推荐一个好用的在线工具网站: 常

    2023年04月25日
    浏览(66)
  • Springboot 自定义 Mybatis拦截器,实现 动态查询条件SQL自动组装拼接(玩具)

    ps:最近在参与3100保卫战,战况很激烈,刚刚打完仗,来更新一下之前写了一半的博客。 该篇针对日常写查询的时候,那些动态条件sql 做个简单的封装,自动生成(抛砖引玉,搞个小玩具,不喜勿喷)。 来看看我们平时写那些查询,基本上都要写的一些动态sql:   一个字段

    2024年02月12日
    浏览(45)
  • vue+axios——创建多个实例共用请求拦截器和响应拦截器(403错误信息不提示bug解决)——基础积累

    创建多个实例共用请求拦截器和响应拦截器:使用的是函数的继承,也就是 call() 方法,这个方法第一个参数就是 this ,后面的参数可以是一个也可以是多个。最后一定要记得要 return 出去,否则接口是拿不到数据的。 上面两个文件合并后的处理如下: 在 main.js 中添加如下内容

    2024年02月10日
    浏览(50)
  • Springboot 前后端分离项目中使用拦截器获取不到token或者token为空的问题(OPTION请求被拦截问题)

    转载Springboot前后端分离项目中使用拦截器获取不到token或者token为空的问题(OPTION请求被拦截问题) 目是前后端分离的,并且springboot也配置了跨域功能。 但是配置了JWT功能、以及验证器验证之后却出现了获取不到jwt的问题。获取参数为 null。并且全局异常拦截失效,前端响应

    2024年02月14日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包