这里打印sql利用 mybatis 插件功能
补充知识
Mybatis拦截器能拦截
Executor、ParameterHandler、StatementHandler、ResultSetHandler
四个对象里面的方法
核心逻辑 找到 ClientPreparedStatement.toString() 执行它
这里选用 ParameterHandler 对象拦截 为什么呢
因为所有sql都需要设置参数啊 不区分查询和更新多好
注意自带插件拦截功能会先于拦截的方法执行
也就是 springAOP 中的前置通知
这就引发一个问题之前的sql参数全是占位符
所以需要代理 ParameterHandler
使 ParameterHandler.setParameters() 方法先执行
后执行自定义代理逻辑
package cn.com.XXX.config.custom;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.PreparedStatement;
import java.util.Arrays;
import java.util.List;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.logging.jdbc.PreparedStatementLogger;
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.springframework.objenesis.instantiator.util.UnsafeUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
@Component
@Intercepts(value = { @Signature(type = ParameterHandler.class,
method = "setParameters",
args = { PreparedStatement.class }
) })
public class ParameterHandlerInterceptor implements Interceptor {
private static final String WRAPPING_COM_MYSQL_CJ_JDBC_CLIENT_PREPARED_STATEMENT = "wrapping com.mysql.cj.jdbc.ClientPreparedStatement: ";
@SuppressWarnings("restriction")
public Object intercept(Invocation invocation) throws Throwable {
ParameterHandler handler = (ParameterHandler) invocation.getTarget();
ParameterHandler proxyParameterHandler = ProxyUtil.proxyParameterHandler(handler);
sun.misc.Unsafe unsafe = UnsafeUtils.getUnsafe();
Field targetFiled = invocation.getClass().getDeclaredField("target");
unsafe.putObject(invocation, unsafe.objectFieldOffset(targetFiled), proxyParameterHandler);
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
static class ProxyUtil {
public static final String PREPARE_STATEMENT = "prepareStatement";
public static final String TO_STRING = "toString";
public static final String STATEMEN_NAME = "com.mysql.cj.jdbc.ClientPreparedStatement: ";
public static final List<String> AGENTME_THODS = Arrays
.asList("execute", "executeUpdate", "executeQuery");
public static final PreparedStatement proxyStmt(PreparedStatement stmt) {
return (PreparedStatement) Proxy.newProxyInstance(stmt.getClass().getClassLoader(),
stmt.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (AGENTME_THODS.contains(method.getName())) {
Object invokeMethod = ReflectionUtils.invokeMethod(
ReflectionUtils.findMethod(stmt.getClass(), TO_STRING),
stmt);
String sql = (String) invokeMethod;
if (sql.contains(STATEMEN_NAME)) {
sql = sql.substring(
sql.indexOf(STATEMEN_NAME) + STATEMEN_NAME.length());
}
printSQL(sql);
}
return method.invoke(stmt, args);
}
});
}
public static final ParameterHandler proxyParameterHandler(ParameterHandler handler) {
return (ParameterHandler) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
handler.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(handler, args);
if ("setParameters".equals(method.getName())) {
PreparedStatement statement = null;
InvocationHandler invocationHandler = Proxy
.getInvocationHandler(args[0]);
if (invocationHandler instanceof PreparedStatementLogger) {
statement = ((PreparedStatementLogger) invocationHandler)
.getPreparedStatement();
}
if (statement != null) {
String sqlString = statement.toString();
if (sqlString.contains(
WRAPPING_COM_MYSQL_CJ_JDBC_CLIENT_PREPARED_STATEMENT)) {
sqlString = sqlString.split(
WRAPPING_COM_MYSQL_CJ_JDBC_CLIENT_PREPARED_STATEMENT)[1];
}
printSQL(sqlString);
}
}
return invoke;
}
});
}
public static final void printSQL(String sqlString) {
System.out.println("\033[32;4m"
+ "\r\n;;-- ------------------------------------------------------------------------------------------------------------------------------\r\n"
+ sqlString
+ ";"
+ "\r\n;;-- ------------------------------------------------------------------------------------------------------------------------------\r\n"
+ "\033[0m");
}
}
}
|