通过前文了解到 真正执行的Executor是一个invocationHandler为包装了Interceptor的Plugin的代理类!
Plugin源码如下:
想通过自定义sql执行拦截器来统一打印sql的执行耗时。
配置sqlSessionFactory增加Interceptor:
@Bean(name = "sqlSessionFactory") private SqlSessionFactoryBean sqlSessionFactory(TDataSource mysqlTddlDataSource) throws IOException { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(mysqlTddlDataSource); sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("classpath*:mapper/*Mapper.xml")); sqlSessionFactoryBean.setPlugins(new Interceptor[] { new SqlStatementInterceptor(ServiceNameConstant.ENGINE)}); return sqlSessionFactoryBean; }
拦截器: @Signature标识哪样的类在什么样的方法上进行切面。 详见:
package com.noob.interceptor;import java.util.Properties;import lombok.NoArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.apache.ibatis.cache.CacheKey;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.plugin.Intercepts;import org.apache.ibatis.plugin.Invocation;import org.apache.ibatis.plugin.Plugin;import org.apache.ibatis.plugin.Signature;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.serializer.SerializerFeature;import com.noob.common.constant.CommonConstants;import com.noob.common.constant.CommonConstants.MonitorLogKey;import com.noob.util.CommonUtil;import com.noob.util.NetUtil;/** * 数据库操作性能拦截器,记录耗时 */@Intercepts(value = { @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }), @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class }), @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) })@NoArgsConstructor@Slf4jpublic class SqlStatementInterceptor implements Interceptor { private Properties properties; private String hostIp; public SqlStatementInterceptor(String appName) { properties = new Properties(); properties.setProperty(MonitorLogKey.PROJECT_NAME, appName); hostIp = NetUtil.getLocalAddress(); } @Override public Object intercept(Invocation arg0) throws Throwable { MappedStatement mappedStatement = (MappedStatement) arg0.getArgs()[0]; String sqlId = mappedStatement.getId(); Object returnValue; long start = System.currentTimeMillis(); returnValue = arg0.proceed(); long end = System.currentTimeMillis(); log(sqlId, end - start); return returnValue; } private void log(String sqlId, long costTime) { try { JSONObject logObj = CommonUtil.createGrafanaLog(); logObj.put(MonitorLogKey.LOG_TYPE, CommonConstants.MonitorType.SQL_MONITOR);//sql 耗时 logObj.put(MonitorLogKey.PROJECT_NAME, properties.get(MonitorLogKey.PROJECT_NAME)); logObj.put(MonitorLogKey.HOST_IP, hostIp); logObj.put("sql", sqlId); logObj.put("costTime", costTime); log.info(JSONObject.toJSONString(logObj, SerializerFeature.UseISO8601DateFormat)); } catch (Exception e) { log.warn("output sql costTime fail.", e); } } @Override public Object plugin(Object arg0) { return Plugin.wrap(arg0, this); } @Override public void setProperties(Properties arg0) { this.properties = arg0; }}