import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.Properties;
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})})
@Component
@Configuration
public class SqlStatementInterceptor implements Interceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(SqlStatementInterceptor.class);
@Override
public Object intercept(Invocation invocation) {
// 开始时间
try {
Object target = invocation.getTarget();
System.out.println("-->"+ JSONObject.toJSONString(target));
Field delegate = target.getClass().getDeclaredField("delegate");
delegate.setAccessible(true);
Object delegateObj = delegate.get(target);
System.out.println("fff");
Field[] declaredFields = delegateObj.getClass().getSuperclass().getDeclaredFields();
Field parameterHandler = delegateObj.getClass().getSuperclass().getDeclaredField("boundSql");
parameterHandler.setAccessible(true);
Object parameterHandlerObj = parameterHandler.get(delegateObj);
Field parameterObject = parameterHandlerObj.getClass().getDeclaredField("parameterObject");
parameterObject.setAccessible(true);
Object o = parameterObject.get(parameterHandlerObj);
System.out.println("拦截到执行的sql:--->"+o);
}catch (Exception e){
e.printStackTrace();
}
long start = System.currentTimeMillis();
invocation.getArgs();
try {
return invocation.proceed();
} catch (Exception e) {
LOGGER.error("执行失败!", e);
return null;
} finally {
long end = System.currentTimeMillis();
long time = end - start;
LOGGER.info("cost time {}ms", time);
}
}
@Override
public Object plugin(Object arg0) {
return Plugin.wrap(arg0, new SqlStatementInterceptor());
}
@Override
public void setProperties(Properties arg0) {
}
}
output:
拦截到执行的sql:--->select zni.id,zni.notice_title,zni.notice_content,zni.create_time,zni.update_time,bu.realname as create_user,buu.realname as update_user,dc.dict_value,
(select count(1)
from xxxx_file_info zfi
where zfi.outside_id = zni.id
and type = '0') as file_count
from xxxx_notice_info zni left join base_user bu on bu.userid=zni.create_user left join base_user buu on bu.userid=zni.update_user and bu.userid=buu.userid left join xxxx_DICT_AFTERLOAN@DICTIONARY dc on (dc.type_code='xxxx_dh_notice_status' and dc.dict_code=zni.notice_status ) where 1=1 order by is_top desc,create_time desc
这里配置了拦截器,拦截指定类中方法的执行,说白了就是标记,让spring 生成代理类,然后每次调用调用都执行我们的方法
Intercepts注解用于定义要拦截的方法集合,Signature 注解定义要拦截的方法定义,type定义要拦截的类,method 定义方法名,args定义参数列表,定义好后spring 在启动的时候会根据这个注解来生成代理类,这样每次执行指定类里面的方法就会被我们定义的拦截器拦截掉
public class PreparedStatementHandler extends BaseStatementHandler {
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
这个delegate字段是这个类型的,然后我们要获得他的名字叫做boundSql的字段,然后这个字段在这个父类里面
public abstract class BaseStatementHandler implements StatementHandler {
protected final Configuration configuration;
protected final ObjectFactory objectFactory;
protected final TypeHandlerRegistry typeHandlerRegistry;
protected final ResultSetHandler resultSetHandler;
protected final ParameterHandler parameterHandler;
protected final Executor executor;
protected final MappedStatement mappedStatement;
protected final RowBounds rowBounds;
protected BoundSql boundSql;
因此,这里我们获得这个boundSql字段要这样
Field parameterHandler = delegateObj.getClass().getSuperclass().getDeclaredField("boundSql");
其他没什么要注意的了,主要就是参数列表对象的分析