前言
在执行查询操作过程中,控制台经常会打印如下的几条日志:
==> Preparing: select count(*) from ws_data WHERE ( ack = ? )
==> Parameters: false(Boolean)
<== Total: 1
下面对这几条日志的打印流程分别进行分析
一 日志的创建
在执行MappedStatement.Builder( )时,创建日志对象
mappedStatement.statementLog = LogFactory.getLog(logId);
二 日志的获取
在SimpleExecutor中执行prepareStatement的时候,日志被获取出来
stmt = prepareStatement(handler, ms.getStatementLog());
prepareStatement( )
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
getConnection( )
protected Connection getConnection(Log statementLog) throws SQLException {
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
//如果第debug级别的日志,这里创建了一个代理对象Connection
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
}
newInstance( )
public static Connection newInstance(Connection conn, Log statementLog, int queryStack) {
//创建ConnectionLogger
InvocationHandler handler = new ConnectionLogger(conn, statementLog, queryStack);
ClassLoader cl = Connection.class.getClassLoader();
//动态代理,返回带日志功能的Connection
return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler);
}
三 日志的调用
上面为Connection创建了代理对象,在Connection调用方法的过程中会进入日志拦截器的invoke方法。
(1)ConnectionLogger的invoke( )
@Override
public Object invoke(Object proxy, Method method, Object[] params)
throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, params);
}
//如果是prepareStatement或prepareCall
if ("prepareStatement".equals(method.getName()) || "prepareCall".equals(method.getName())) {
if (isDebugEnabled()) {
//这里打印出了前言中第一条sql日志
debug(" Preparing: " + removeExtraWhitespace((String) params[0]), true);
}
//反射调用目标方法
PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
//为PreparedStatement创建有日志功能的代理对象PreparedStatementLogger
stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);
return stmt;
//如果是createStatement
} else if ("createStatement".equals(method.getName())) {
Statement stmt = (Statement) method.invoke(connection, params);
//创建代理对象StatementLogger
stmt = StatementLogger.newInstance(stmt, statementLog, queryStack);
return stmt;
} else {
return method.invoke(connection, params);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
(2)PreparedStatementLogger的invoke( )
@Override
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, params);
}
//包括execute、executeUpdate、executeQuery、addBatch方法
if (EXECUTE_METHODS.contains(method.getName())) {
if (isDebugEnabled()) {
//这里打印出了前言中的第二条sql日志
debug("Parameters: " + getParameterValueString(), true);
}
clearColumnInfo();
//executeQuery方法
if ("executeQuery".equals(method.getName())) {
ResultSet rs = (ResultSet) method.invoke(statement, params);
return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
} else {
return method.invoke(statement, params);
}
} else if (SET_METHODS.contains(method.getName())) {
if ("setNull".equals(method.getName())) {
setColumn(params[0], null);
} else {
setColumn(params[0], params[1]);
}
return method.invoke(statement, params);
} else if ("getResultSet".equals(method.getName())) {
//getResultSet方法
ResultSet rs = (ResultSet) method.invoke(statement, params);
//同样的套路创建带有日志功能的ResultSet
return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
} else if ("getUpdateCount".equals(method.getName())) {
int updateCount = (Integer) method.invoke(statement, params);
if (updateCount != -1) {
debug(" Updates: " + updateCount, false);
}
return updateCount;
} else {
return method.invoke(statement, params);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
(3)ResultSetLogger的invoke( )
@Override
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, params);
}
Object o = method.invoke(rs, params);
if ("next".equals(method.getName())) {
if ((Boolean) o) {
rows++;
if (isTraceEnabled()) {
ResultSetMetaData rsmd = rs.getMetaData();
final int columnCount = rsmd.getColumnCount();
if (first) {
first = false;
//打印Columns:
printColumnHeaders(rsmd, columnCount);
}
//打印Row:
printColumnValues(columnCount);
}
} else {
//这里打印出了前言中的第三条sql日志
debug(" Total: " + rows, false);
}
}
clearColumnInfo();
return o;
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}