溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

SpringBoot整合Mybatis自定義攔截器不起作用怎么辦

發(fā)布時(shí)間:2021-09-24 16:50:12 來(lái)源:億速云 閱讀:1931 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹了SpringBoot整合Mybatis自定義攔截器不起作用怎么辦,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

    SpringBoot整合Mybatis自定義攔截器不起作用

    Mybatis插件生效的方式:

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

    該方式和Spring無(wú)關(guān),是通過(guò)反射的形式創(chuàng)建插件對(duì)象,此時(shí)會(huì)執(zhí)行org.apache.ibatis.plugin.Interceptor#setProperties方法,以讀取配置參數(shù)。

    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容器整合

    網(wǎng)上很多方案說(shuō):mybatis自定義攔截器上加上@Component注解便可以生效。但是我將自定義攔截器放入到Spring容器中,自定義攔截器卻失效了。

    然后找到了springboot配置多數(shù)據(jù)源后mybatis攔截器失效文章,說(shuō)是自定義配置了數(shù)據(jù)源導(dǎo)致了攔截器失效。

    2.1 mybatis的自動(dòng)裝載

    源碼位置: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;
       //會(huì)依賴注入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());
        //手動(dòng)放入到了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();
      }
       ...
    }

    上面源碼中:自動(dòng)注入了Interceptor[]數(shù)組(我們只需將mybatis的自定義攔截器對(duì)象放入到Spring容器中)。后續(xù)放入了sqlSessionFactory中。

    但是項(xiàng)目中雖然自定義配置了sqlSessionFactory類,但卻未設(shè)置factory.setPlugins(this.interceptors);。導(dǎo)致即使將自定義攔截器放入到Spring容器,但卻不生效。

    解決方法,需要手動(dòng)修改自定義的sqlSessionFactory類。

    3. 在mybatis-config.xml配置又放入Spring容器

    這種情況下,mybatis自定義攔截器會(huì)被執(zhí)行兩次。即在mybatis-config.xml配置的攔截器會(huì)通過(guò)反射的方式創(chuàng)建攔截器,放入Spring容器的攔截器也會(huì)被初始化。

    源碼位置:org.mybatis.spring.SqlSessionFactoryBean#buildSqlSessionFactory

    protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
        Configuration configuration;
        ...讀取屬性中的plugins,即org.mybatis.spring.SqlSessionFactoryBean#setPlugins設(shè)置的。
        if (!isEmpty(this.plugins)) {
            for (Interceptor plugin: this.plugins) {
                configuration.addInterceptor(plugin);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Registered plugin: '" + plugin + "'");
                }
            }
        }
        ...解析xml配置(通過(guò)反射創(chuàng)建攔截器對(duì)象)
        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);
    }

    最終會(huì)執(zhí)行到:

    private void pluginElement(XNode parent) throws Exception {
        if (parent != null) {
            for (XNode child: parent.getChildren()) {
                String interceptor = child.getStringAttribute("interceptor");
                Properties properties = child.getChildrenAsProperties();
                //反射創(chuàng)建mybatis的插件。
                Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
                interceptorInstance.setProperties(properties);
                configuration.addInterceptor(interceptorInstance);
            }
        }
    }

    SpringBoot 自定義Mybatis攔截器

    開(kāi)發(fā)過(guò)程中經(jīng)?;匦枰獙?duì)要執(zhí)行的sql加以自定義處理,比如分頁(yè),計(jì)數(shù)等。通過(guò) MyBatis 提供的強(qiáng)大機(jī)制,使用插件是非常簡(jiǎn)單的,只需實(shí)現(xiàn) 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加上這個(gè)攔截器,有三種方法,前兩種方法在啟動(dòng)項(xiàng)目時(shí)不會(huì)自動(dòng)調(diào)用自定義攔截器的setProperties方法。

    第一種

    直接給自定義攔截器添加一個(gè)@Component注解,當(dāng)調(diào)用sql時(shí)結(jié)果如下,可以看到攔截器生效了,但是啟動(dòng)時(shí)候并沒(méi)有自動(dòng)調(diào)用setProperties方法。

    SpringBoot整合Mybatis自定義攔截器不起作用怎么辦

    第二種

    在配置類里添加攔截器,這種方法結(jié)果同上,也不會(huì)自動(dòng)調(diào)用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屬性不能同時(shí)指定

    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>

    可以看到,在啟動(dòng)項(xiàng)目的時(shí)候setProperties被自動(dòng)調(diào)用了

    SpringBoot整合Mybatis自定義攔截器不起作用怎么辦

    前兩種方法可以在初始化自定義攔截器的時(shí)候通過(guò) @Value 注解直接初始化需要的參數(shù)。

    感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“SpringBoot整合Mybatis自定義攔截器不起作用怎么辦”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI