大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
最近项目用上了mybatis, 但是想像hibernate那样能打印sql, 于是写了个基于mybatis拦截器的sql打印, 参考这个https://blog.22xcode.com/post/78
然后, 碰到了问题, 拦截器会重复输出一句sql
mybatis sql: SELECT id, name FROM user
mybatis sql: SELECT id, name FROM user
排查下, 项目里跟mybatis有关的就只有pagehelper了, 猜测可能是pagehelper 为了分页再发了一条算总数count的sql, 而打印sql的拦截器没有获取到count查询的完整sql, 所以看上去发了两遍一样的sql
网上找了下拦截器的资料, 发现基本都是这个样子
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Th2xecl-1656070640683)(/storage/thumbnails/_signature/3PUPLE2S14QE5OG0JJL7RED3FL.png)]
大概意思就是后定义/加载的拦截器会先执行.
于是更改配置, 将sql打印拦截器在pagehelper的拦截器之后执行
@Autowired
private List<SqlSessionFactory> sqlSessionFactoryList;
/**
* 在分页拦截器后加载
*/
@Autowired
PageHelperAutoConfiguration pageHelperAutoConfiguration;
@PostConstruct
public void registerInterceptor() {
if (enableSqlLog) {
MybatisSqlLogInterceptor interceptor = new MybatisSqlLogInterceptor();
for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
Configuration configuration = sqlSessionFactory.getConfiguration();
if (!containsInterceptor(configuration, interceptor)) {
configuration.addInterceptor(interceptor);
}
}
log.warn("[mybatis sql log]已启用, 请检查当前是否为开发环境");
} else {
log.info("[mybatis sql log]已禁用");
}
}
其实也试了下
@AutoConfigureAfter
, 但是发现不起作用, 后续再琢磨下吧.
配置完成, 再次执行查询, sql只打印一次, 说明sql打印拦截器在分页拦截器之前被调用, 完成
但是为什么先加载的拦截器反而后执行, 网上好像没啥资料, 那就只能自己翻翻源码了.
debug看了下, 找到了这个类
package org.apache.ibatis.plugin;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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);
}
}
InterceptorChain顾名思义, 拦截链, 可以看到项目定义的拦截器都在InterceptorChain内用ArrayList存储起来
核心是这个InterceptorChain#pluginAll
这个方法
解析下
在pluginAll
方法中, 遍历interceptors
, 为目标对象创建代理.
即, 在这一步, 先加载的拦截器会优先被遍历, 会优先
对目标对象进行代理,
后加载的拦截器, 在原有的代理之上再进行代理, 一层包一层, 类似洋葱.
当方法被调用时, 会先执行最外层的代理方法
.
所以, 先加载到的拦截器, 反而是最后执行
.
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/196611.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...