千家信息网

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

发表于:2025-01-18 作者:千家信息网编辑
千家信息网最后更新 2025年01月18日,这篇文章主要介绍了SpringBoot整合Mybatis自定义拦截器不起作用怎么办,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Spr
千家信息网最后更新 2025年01月18日SpringBoot整合Mybatis自定义拦截器不起作用怎么办

这篇文章主要介绍了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的全局配置:

                                                                                                                                                        

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

    @Configurationpublic 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
                                                         

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

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

    感谢你能够认真阅读完这篇文章,希望小编分享的"SpringBoot整合Mybatis自定义拦截器不起作用怎么办"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

    0