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對象的解析
在這裏插入圖片描述
在這裏插入圖片描述
這裏有點坑,

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

其他沒什麼要注意的了,主要就是參數列表對象的分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章