Spring Boot 定义拦截器,拦截所有执行的sql

Spring Boot 定义拦截器,拦截所有执行的sql

文章目录

  • Spring Boot 定义拦截器,拦截所有执行的sql
        • 代码实现
        • 一些说明

代码实现


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 在启动的时候会根据这个注解来生成代理类,这样每次执行指定类里面的方法就会被我们定义的拦截器拦截掉

比较重要的就是invocation对象的解析
Spring Boot 定义拦截器,拦截所有执行的sql_第1张图片
Spring Boot 定义拦截器,拦截所有执行的sql_第2张图片
这里有点坑,

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");

其他没什么要注意的了,主要就是参数列表对象的分析

你可能感兴趣的:(Java,ssm,Spring,Spring,Boot,Sql,拦截)