lodsve.mybatis.plugins.monitor.MonitorInterceptor Maven / Gradle / Ivy
/*
* Copyright (C) 2018 Sun.Hao
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package lodsve.mybatis.plugins.monitor;
import lodsve.mybatis.exception.MyBatisException;
import lodsve.mybatis.utils.MyBatisUtils;
import lodsve.mybatis.utils.SqlUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Proxy;
import java.sql.Statement;
import java.util.Properties;
/**
* mybatis性能监控.
*
* @author sunhao([email protected])
* @date 2017/6/12 下午8:23
*/
@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})})
public class MonitorInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(MonitorInterceptor.class);
/**
* SQL 执行最大时长,超过自动停止运行,有助于发现问题。
*/
private long maxTime = 0;
/**
* SQL 是否格式化
*/
private boolean format = false;
/**
* 是否写入日志文件
* true 写入日志文件,不阻断程序执行!
* 超过设定的最大执行时长异常提示!
*/
private boolean writeInLog = false;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Statement statement;
Object firstArg = invocation.getArgs()[0];
if (Proxy.isProxyClass(firstArg.getClass())) {
statement = (Statement) SystemMetaObject.forObject(firstArg).getValue("h.statement");
} else {
statement = (Statement) firstArg;
}
try {
statement.getClass().getDeclaredField("stmt");
statement = (Statement) SystemMetaObject.forObject(statement).getValue("stmt.statement");
} catch (Exception e) {
// do nothing
}
// 获取执行 SQL
String originalSql = statement.toString();
int index = originalSql.indexOf(':');
if (index > 0) {
originalSql = originalSql.substring(index + 1);
}
// 计算执行 SQL 耗时
long start = System.currentTimeMillis();
Object result = invocation.proceed();
long timing = System.currentTimeMillis() - start;
// 格式化 SQL 打印执行结果
Object target = MyBatisUtils.processTarget(invocation.getTarget());
MappedStatement ms = MyBatisUtils.getValue(target, "delegate.mappedStatement");
StringBuilder formatSql = new StringBuilder();
formatSql.append(" Time:").append(timing);
formatSql.append(" ms - ID:").append(ms.getId());
formatSql.append("\n Execute SQL:").append(SqlUtils.sqlFormat(originalSql, format)).append("\n");
if (writeInLog) {
if (maxTime >= 1 && timing > maxTime) {
logger.error(formatSql.toString());
} else {
logger.debug(formatSql.toString());
}
} else {
System.err.println(formatSql.toString());
if (maxTime >= 1 && timing > maxTime) {
throw new MyBatisException(" The SQL execution time is too large, please optimize ! ");
}
}
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties prop) {
}
public void setMaxTime(long maxTime) {
this.maxTime = maxTime;
}
public void setFormat(boolean format) {
this.format = format;
}
public void setWriteInLog(boolean writeInLog) {
this.writeInLog = writeInLog;
}
}