網(wǎng)站首頁 編程語言 正文
結(jié)論:攔截同一個(gè)方法的攔截器和我們?cè)趍ybatis-config.xml文件中的順序相反
1. plugin生效的兩種方式
推薦閱讀——plugin生效的方式
源碼位置:mybatis的自動(dòng)加載:org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration#sqlSessionFactory
public class MybatisAutoConfiguration {
private static Log log = LogFactory.getLog(MybatisAutoConfiguration.class);
//讀取Spring容器中的所有的plugin插件
@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())) {
//讀取mybatis-config.xml的地址
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
factory.setConfiguration(properties.getConfiguration());
//放入插件
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();
}
}
注意:SqlSessionFactoryBean
實(shí)現(xiàn)了InitializingBean
接口,在afterPropertiesSet()
方法中將執(zhí)行org.mybatis.spring.SqlSessionFactoryBean#buildSqlSessionFactory
方法去讀取ConfigLocation的xml文件,解析plugin并放入集合中。
結(jié)論:spring容器的plugin先放入到集合中,后續(xù)將
mybatis-config.xml
的plugin按先后順序放入到集合中。
2. plugin切面執(zhí)行的順序
源碼位置:org.apache.ibatis.plugin.InterceptorChain
該方法會(huì)對(duì)target代理,并且對(duì)代理類在進(jìn)行代理。一層一層的增強(qiáng)target類,故越靠后的Interceptor越先執(zhí)行。
public class InterceptorChain {
private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
public Object pluginAll(Object target) {
//將項(xiàng)目啟動(dòng)時(shí)注冊(cè)的interceptors拿出來,執(zhí)行plugin方法。
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);
}
}
而plugin方法:
@Slf4j
@Intercepts(
@Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class }))
public class A1Interceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
log.info("A1 before...");
Object proceed = invocation.proceed();
log.info("A1 after...");
return proceed;
}
/**
* 將插件對(duì)象加入到攔截器鏈中
* @param target
* @return
*/
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
實(shí)際上會(huì)調(diào)用Plugin.wrap(target, this)
方法。
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;
}
wrap方法會(huì)創(chuàng)建代理對(duì)象。
代理對(duì)象.png
wrapper()
方法對(duì)target對(duì)象一層一層的代理。即before切面執(zhí)行的順序與放入plugins的順序相反。
原文鏈接:https://blog.csdn.net/LiZhen314/article/details/125760408
相關(guān)推薦
- 2022-08-16 Kotlin空安全空類型淺談_Android
- 2022-04-28 C#中Razor模板引擎簡(jiǎn)單使用_C#教程
- 2022-04-30 C語言程序環(huán)境中的預(yù)處理詳解_C 語言
- 2022-03-25 Redis分布式鎖如何實(shí)現(xiàn)續(xù)期_Redis
- 2022-06-09 Python字符串的索引與切片_python
- 2022-04-28 C#實(shí)現(xiàn)Windows服務(wù)測(cè)試與調(diào)試_C#教程
- 2022-06-17 C語言深入探索動(dòng)態(tài)內(nèi)存分配的使用_C 語言
- 2022-09-26 React?Native?中添加自定義字體的方法_React
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支