栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

来来来,继续打印sql,利用 mybatis 插件功能

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

来来来,继续打印sql,利用 mybatis 插件功能

这里打印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
		ParameterHandler proxyParameterHandler = ProxyUtil.proxyParameterHandler(handler);
		// 偷天换日(换掉 invocation 的目标对象为代理对象)
		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 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 {
							// 重写executeQuery方法
							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 {
							// 重写executeQuery方法
							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("33[32;4m"
					+ "rn;;-- ------------------------------------------------------------------------------------------------------------------------------rn"
						+ sqlString
						+ ";"
						+ "rn;;-- ------------------------------------------------------------------------------------------------------------------------------rn"
						+ "33[0m");
		}
	}
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/763422.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号