SpringBoot整合Mybatis自定義攔截器不起作用的處理方案
SpringBoot整合Mybatis自定義攔截器不起作用
Mybatis插件生效的方式:
1. 原始的讀取mybatis-config.xml文件
該方式和Spring無關(guān),是通過反射的形式創(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)上很多方案說:mybatis自定義攔截器上加上@Component注解便可以生效。但是我將自定義攔截器放入到Spring容器中,自定義攔截器卻失效了。
然后找到了springboot配置多數(shù)據(jù)源后mybatis攔截器失效文章,說是自定義配置了數(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ì)通過反射的方式創(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配置(通過反射創(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攔截器
開發(fā)過程中經(jīng)常回需要對(duì)要執(zhí)行的sql加以自定義處理,比如分頁(yè),計(jì)數(shù)等。通過 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í)候并沒有自動(dòng)調(diào)用setProperties方法。

第二種
在配置類里添加攔截器,這種方法結(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)用了

前兩種方法可以在初始化自定義攔截器的時(shí)候通過 @Value 注解直接初始化需要的參數(shù)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
MyBatis實(shí)現(xiàn)三級(jí)樹查詢的示例代碼
在實(shí)際項(xiàng)目開發(fā)中,樹形結(jié)構(gòu)的數(shù)據(jù)查詢是一個(gè)非常常見的需求,比如組織架構(gòu)、菜單管理、地區(qū)選擇等場(chǎng)景都需要處理樹形數(shù)據(jù),本文將詳細(xì)講解如何使用MyBatis實(shí)現(xiàn)三級(jí)樹形數(shù)據(jù)的查詢,需要的朋友可以參考下2024-12-12
解決try-catch捕獲異常信息后Spring事務(wù)失效的問題
這篇文章主要介紹了解決try-catch捕獲異常信息后Spring事務(wù)失效的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
JAVA實(shí)現(xiàn)Base64編碼的三種方式
本文主要介紹了JAVA實(shí)現(xiàn)Base64編碼的三種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
java實(shí)現(xiàn)多人多牌數(shù)比較游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)多人多牌數(shù)比較游戲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
SpringBoot啟動(dòng)多數(shù)據(jù)源找不到合適的驅(qū)動(dòng)類問題
這篇文章主要介紹了SpringBoot啟動(dòng)多數(shù)據(jù)源找不到合適的驅(qū)動(dòng)類問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
web.xml中servlet, bean, filter, listenr 加載順序_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了web.xml中servlet, bean, filter, listenr 加載順序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08

