ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

MyBatis日志模块解析:集成第三方日志框架

MyBatis日志模块解析:集成第三方日志框架 1. 项目概述当Python遇上大模型人才需求分析最近半年大模型技术彻底改变了AI行业的就业格局。作为长期关注技术趋势的从业者我尝试用Python对全网大模型相关岗位数据进行了一次深度挖掘和可视化分析。这个项目不仅帮我理清了当前市场需求也为求职者和招聘方提供了直观的市场洞察。通过爬取主流招聘平台数据结合自然语言处理技术我们能够清晰看到掌握PyTorch和Transformer架构的工程师薪资溢价达到40%而同时具备大模型部署和业务落地能力的人才最为稀缺。本文将完整呈现从数据采集到可视化分析的全流程特别适合三类读者准备转型大模型领域的技术人员、需要制定招聘策略的HR以及对数据分析感兴趣Python开发者。2. 核心需求与技术选型2.1 为什么要分析大模型人才需求2023年被称为大模型应用元年但市场供需存在严重信息不对称。企业不清楚该招聘什么技能组合的人才求职者也不明白该重点提升哪些能力。通过数据驱动的方式呈现市场真实需求可以解决以下痛点求职者盲目学习避免花费数月学习非核心技能如过时的机器学习框架企业精准招聘识别真正影响大模型岗位绩效的关键能力项教育机构课程设计根据市场需求动态调整培训内容2.2 技术栈构建思路项目采用典型的数据分析流水线架构关键技术选型基于三个原则数据处理效率PandasNumpy组合处理结构化数据Dask应对海量非结构化数据NLP处理需求Jieba分词处理中文JDTransformers库提取技术关键词可视化交互性PlotlyPyEcharts实现动态图表Dash构建交互看板关键决策放弃使用Scrapy框架改用异步请求库aiohttpBeautifulSoup组合。实测在反爬严格的招聘网站这种方案成功率提升60%且能更好模拟人类浏览行为。3. 数据采集与清洗实战3.1 构建智能爬虫系统招聘数据采集面临三大挑战反爬机制、动态加载、数据结构异构。我们的解决方案async def fetch_job_detail(url): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36, Referer: https://www.liepin.com/ } async with aiohttp.ClientSession() as session: try: async with session.get(url, headersheaders, proxyNone) as resp: if resp.status 200: return await resp.text() except Exception as e: logging.error(f请求失败: {str(e)}) return None关键参数说明请求间隔随机化2-5秒浮动避免触发频率限制异常重试机制对503/429状态码自动退避重试数据指纹去重MD5哈希处理职位描述文本3.2 数据清洗的七个关键步骤原始数据存在的典型问题薪资范围格式混乱20-40k·15薪 vs 面议技能要求描述模糊熟悉大模型相关技术公司规模标准不一100-499人 vs C轮融资清洗流程示例def clean_salary(text): if k in text: lower float(re.search(r(\d)k, text).group(1)) upper float(re.search(r(\d)k, text.split(-)[-1]).group# 1. 概述 本文我们来分享 MyBatis 的日志模块对应 logging 包。如下图所示[![logging 包](http://static.iocoder.cn/images/MyBatis/2020_01_07/01.png)](http://static.iocoder.cn/images/MyBatis/2020_01_07/01.png)logging 包 在 [《精尽 MyBatis 源码解析 —— 项目结构一览》](http://svip.iocoder.cn/MyBatis/intro) 中简单介绍了这个模块如下 无论在开发测试环境中还是在线上生产环境中日志在整个系统中的地位都是非常重要的。良好的日志功能可以帮助开发人员和测试人员快速定位 Bug 代码也可以帮助运维人员快速定位性能瓶颈等问题。目前的 Java 世界中存在很多优秀的日志框架例如 Log4j、 Log4j2、Slf4j 等。 MyBatis 作为一个设计优良的框架除了提供详细的日志输出信息还要能够集成多种日志框架其日志模块的一个主要功能就是**集成第三方日志框架**。 本文涉及的类如下图所示img srchttp://static.iocoder.cn/images/MyBatis/2020_01_07/02.png alt类图 stylezoom:80%; / - 从图的**最下面**我们可以看到 MyBatis 集成多种第三方日志框架。但是实际上MyBatis 并没有直接引入第三方日志框架的依赖而是通过**适配器模式**调用第三方日志框架的 API 来实现打印日志。这样就不会因为强制使用某个日志框架而导致不方便项目开发。当然实际上只要引入任意一个第三方日志框架即可因为 MyBatis 会按照顺序查找支持的第三方日志框架是否在存在。 - 从图的**中间**我们可以看到 MyBatis 自身定义了 Log 接口来**统一**日志的访问。而 LogFactory 工厂负责创建对应的 Log 对象。 - 从图的**最上面**我们可以看到 MyBatis 对 JDK 的 java.util.logging.Logger 也进行了适配。 # 2. Log org.apache.ibatis.logging.Log MyBatis Log 接口。代码如下 java public interface Log { boolean isDebugEnabled(); boolean isTraceEnabled(); void error(String s, Throwable e); void error(String s); void debug(String s); void trace(String s); void warn(String s); }定义了日志的接口。不同的日志框架可以实现该接口进行对应的适配。2.1 LogFactoryorg.apache.ibatis.logging.LogFactoryLog 工厂类。代码如下public final class LogFactory { /** * Marker to be used by logging implementations that support markers. */ public static final String MARKER MYBATIS; /** * 使用的 Log 的构造方法 */ private static Constructor? extends Log logConstructor; static { // 1 逐个尝试判断使用哪个 Log 的实现类即初始化 logConstructor 属性 tryImplementation(LogFactory::useSlf4jLogging); tryImplementation(LogFactory::useCommonsLogging); tryImplementation(LogFactory::useLog4J2Logging); tryImplementation(LogFactory::useLog4JLogging); tryImplementation(LogFactory::useJdkLogging); tryImplementation(LogFactory::useNoLogging); } private LogFactory() { // disable construction } public static Log getLog(Class? clazz) { return getLog(clazz.getName()); } public static Log getLog(String logger) { try { return logConstructor.newInstance(logger); } catch (Throwable t) { throw new LogException(Error creating logger for logger logger . Cause: t, t); } } public static synchronized void useCustomLogging(Class? extends Log clazz) { setImplementation(clazz); } public static synchronized void useSlf4jLogging() { setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class); } public static synchronized void useCommonsLogging() { setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class); } public static synchronized void useLog4JLogging() { setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class); } public static synchronized void useLog4J2Logging() { setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class); } public static synchronized void useJdkLogging() { setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class); } public static synchronized void useStdOutLogging() { setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class); } public static synchronized void useNoLogging() { setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class); } private static void tryImplementation(Runnable runnable) { if (logConstructor null) { try { runnable.run(); } catch (Throwable t) { // ignore } } } private static void setImplementation(Class? extends Log implClass) { try { // 获得参数为 String 的构造方法 Constructor? extends Log candidate implClass.getConstructor(String.class); // 创建 Log 对象 Log log candidate.newInstance(LogFactory.class.getName()); if (log.isDebugEnabled()) { log.debug(Logging initialized using implClass adapter.); } // 创建成功意味着可以使用设置为 logConstructor logConstructor candidate; } catch (Throwable t) { throw new LogException(Error setting Log implementation. Cause: t, t); } } }MARKER静态属性标记目前暂时没用到。logConstructor静态属性使用的 Log 的构造方法在1静态代码块中初始化。1处在#setImplementation(Class? extends Log implClass)方法中我们可以看到MyBatis 会尝试使用指定的 Log 实现类如果创建失败会抛出 LogException 异常。否则会初始化logConstructor属性。1处我们可以看到MyBatis 会尝试使用 SLF4J、CommonsLogging、Log4J2、Log4J、JdkLogging 的日志实现类按照顺序直到有一个成功为止。否则使用 NoLoggingImpl 实现类即不打印日志。#getLog(...)静态方法获得 Log 对象。3. 第三方日志框架集成3.1 Slf4jImplorg.apache.ibatis.logging.slf4j.Slf4jImpl实现 Log 接口SLF4J 实现类。代码如下public class Slf4jImpl implements Log { private Log log; public Slf4jImpl(String clazz) { // 使用 SLF4J 的 LoggerFactory 获得 SLF4J 的 Logger 对象 Logger logger LoggerFactory.getLogger(clazz); // 如果是 LocationAwareLogger 需要增加判断因为需要实现的方法不同 if (logger instanceof LocationAwareLogger) { try { // check for slf4j 1.6 method signature logger.getClass().getMethod(log, Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class); log new Slf4jLocationAwareLoggerImpl((LocationAwareLogger) logger); return; } catch (SecurityException | NoSuchMethodException e) { // fail-back to Slf4jLoggerImpl } } // Logger is not LocationAwareLogger or slf4j version 1.6 log new Slf4jLoggerImpl(logger); } Override public boolean isDebugEnabled() { return log.isDebugEnabled(); } Override public boolean isTraceEnabled() { return log.isTraceEnabled(); } Override public void error(String s, Throwable e) { log.error(s, e); } Override public void error(String s) { log.error(s); } Override public void debug(String s) { log.debug(s); } Override public void trace(String s) { log.trace(s); } Override public void warn(String s) { log.warn(s); } }在构造方法中我们可以看到使用 SLF4J 的org.slf4j.LoggerFactory获得org.slf4j.Logger对象。而后根据不同的情况创建不同的 Slf4jImpl 实现类如果是org.slf4j.spi.LocationAwareLogger对象则创建 Slf4jLocationAwareLoggerImpl 对象。如果是普通的org.slf4j.Logger对象则创建 Slf4jLoggerImpl 对象。具体的每个方法调用对应的log对应的方法。3.1.1 Slf4jLoggerImplorg.apache.ibatis.logging.slf4j.Slf4jLoggerImpl实现 Log 接口Slf4jLogger 实现类。代码如下class Slf4jLoggerImpl implements Log { private Logger log; public Slf4jLoggerImpl(Logger logger) { log logger; } Override public boolean isDebugEnabled() { return log.isDebugEnabled(); } Override public boolean isTraceEnabled() { return log.isTraceEnabled(); } Override public void error(String s, Throwable e) { log.error(s, e); } Override public void error(String s) { log.error(s); } Override public void debug(String s) { log.debug(s); } Override public void trace(String s) { log.trace(s); } Override public void warn(String s) { log.warn(s); } }3.1.2 Slf4jLocationAwareLoggerImplorg.apache.ibatis.logging.slf4j.Slf4jLocationAwareLoggerImpl实现 Log 接口Slf4jLocationAwareLogger 实现类。代码如下class Slf4jLocationAwareLoggerImpl implements Log { private static final String FQCN Slf4jImpl.class.getName(); private LocationAwareLogger logger; public Slf4jLocationAwareLoggerImpl(LocationAwareLogger logger) { this.logger logger; } Override public boolean isDebugEnabled() { return logger.isDebugEnabled(); } Override public boolean isTraceEnabled() { return logger.isTraceEnabled(); } Override public void error(String s, Throwable e) { logger.log(null, FQCN, LocationAwareLogger.ERROR_INT, s, null, e); } Override public void error(String s) { logger.log(null, FQCN, LocationAwareLogger.ERROR_INT, s, null, null); } Override public void debug(String s) { logger.log(null, FQCN, LocationAwareLogger.DEBUG_INT, s, null, null); } Override public void trace(String s) { logger.log(null, FQCN, LocationAwareLogger.TRACE_INT, s, null, null); } Override public void warn(String s) { logger.log(null, FQCN, LocationAwareLogger.WARN_INT, s, null, null); } }差异点在于打印日志的方法需要使用FQCN属性。3.2 JakartaCommonsLoggingImplorg.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl实现 Log 接口JakartaCommonsLogging 实现类。代码如下public class JakartaCommonsLoggingImpl implements Log { private Log log; public JakartaCommonsLoggingImpl(String clazz) { // 使用 Commons Logging 的 LogFactory 获得 Log 对象 log LogFactory.getLog(clazz); } Override public boolean isDebugEnabled() { return log.isDebugEnabled(); } Override public boolean isTraceEnabled() { return log.isTraceEnabled(); } Override public void error(String s, Throwable e) { log.error(s, e); } Override public void error(String s) { log.error(s); } Override public void debug(String s) { log.debug(s); } Override public void trace(String s) { log.trace(s); } Override public void warn(String s) { log.warn(s); } }在构造方法中我们可以看到使用 Commons Logging 的org.apache.commons.logging.LogFactory获得org.apache.commons.logging.Log对象。3.3 Log4jImplorg.apache.ibatis.logging.log4j.Log4jImpl实现 Log 接口Log4j 实现类。代码如下public class Log4jImpl implements Log { private Logger log; public Log4jImpl(String clazz) { // 使用 Log4j 的 Logger 获得 org.apache.log4j.Logger 对象 log Logger.getLogger(clazz); } Override public boolean isDebugEnabled() { return log.isDebugEnabled(); } Override public boolean isTraceEnabled() { return log.isTraceEnabled(); } Override public void error(String s, Throwable e) { log.error(s, e); } Override public void error(String s) { log.error(s); } Override public void debug(String s) { log.debug(s); } Override public void trace(String s) { log.trace(s); } Override public void warn(String s) { log.warn(s); } }在构造方法中我们可以看到使用 Log4j 的org.apache.log4j.Logger获得org.apache.log4j.Logger对象。3.4 Log4j2Implorg.apache.ibatis.logging.log4j2.Log4j2Impl实现 Log 接口Log4j2 实现类。代码如下public class Log4j2Impl implements Log { private Logger log; public Log4j2Impl(String clazz) { // 使用 Log4j2 的 LogManager 获得 org.apache.logging.log4j.Logger 对象 log LogManager.getLogger(clazz); } Override public boolean isDebugEnabled() { return log.isDebugEnabled(); } Override public boolean isTraceEnabled() { return log.isTraceEnabled(); } Override public void error(String s, Throwable e) { log.error(s, e); } Override public void error(String s) { log.error(s); } Override public void debug(String s) { log.debug(s); } Override public void trace(String s) { log.trace(s); } Override public void warn(String s) { log.warn(s); } }在构造方法中我们可以看到使用 Log4j2 的org.apache.logging.log4j.LogManager获得org.apache.logging.log4j.Logger对象。3.5 Jdk14LoggingImplorg.apache.ibatis.logging.jdk14.Jdk14LoggingImpl实现 Log 接口Jdk14Logging 实现类。代码如下public class Jdk14LoggingImpl implements Log { private Logger log; public Jdk14LoggingImpl(String clazz) { // 使用 Java Util Logging 的 Logger 获得 java.util.logging.Logger 对象 log Logger.getLogger(clazz); } Override public boolean isDebugEnabled() { return log.isLoggable(Level.FINE); } Override public boolean isTraceEnabled() { return log.isLoggable(Level.FINER); } Override public void error(String s, Throwable e) { log.log(Level.SEVERE, s, e); } Override public void error(String s) { log.log(Level.SEVERE, s); } Override public void debug(String s) { log.log(Level.FINE, s); } Override public void trace(String s) { log.log(Level.FINER, s); } Override public void warn(String s) { log.log(Level.WARNING, s); } }在构造方法中我们可以看到使用 Java Util Logging 的java.util.logging.Logger获得java.util.logging.Logger对象。3.6 StdOutImplorg.apache.ibatis.logging.stdout.StdOutImpl实现 Log 接口StdOut 实现类。代码如下public class StdOutImpl implements Log { public StdOutImpl(String clazz) { // Do Nothing } Override public boolean isDebugEnabled() { return true; } Override public boolean isTraceEnabled() { return true; } Override public void error(String s, Throwable e) { System.err.println(s); e.printStackTrace(System.err); } Override public void error(String s) { System.err.println(s); } Override public void debug(String s) { System.out.println(s); } Override public void trace(String s) { System.out.println(s); } Override public void warn(String s) { System.out.println(s); } }基于System.out和System.err实现。3.7 NoLoggingImplorg.apache.ibatis.logging.nologging.NoLoggingImpl实现 Log 接口NoLogging 实现类。代码如下public class NoLoggingImpl implements Log { public NoLoggingImpl(String clazz) { // Do Nothing } Override public boolean isDebugEnabled() { return false; } Override public boolean isTraceEnabled() { return false; } Override public void error(String s, Throwable e) { // Do Nothing } Override public void error(String s) { // Do Nothing } Override public void debug(String s) { // Do Nothing } Override public void trace(String s) { // Do Nothing } Override public void warn(String s) { // Do Nothing } }空实现。4. BaseJdbcLogger在logging包中BaseJdbcLogger和其子类实现将 JDBC 的操作打印成日志。整体类图如下类图4.1 BaseJdbcLoggerorg.apache.ibatis.logging.jdbc.BaseJdbcLogger实现 Log 接口BaseJdbcLogger 抽象类。代码如下public abstract class BaseJdbcLogger implements Log { /** * 统计字段相关的属性的 KEY 集合 */ protected static final SetString SET_METHODS new HashSet(); /** * 执行 SQL 相关的属性的 KEY 集合 */ protected static final SetString EXECUTE_METHODS new HashSet(); /** * SET 方法的前缀 */ private static final String SET_METHOD_PREFIX set; /** * 执行方法的集合 */ private static final String EXECUTE_METHOD_PREFIX execute; static { // 初始化 SET_METHODS Method[] methods PreparedStatement.class.getMethods(); for (Method method : methods) { String methodName method.getName(); if (methodName.startsWith(SET_METHOD_PREFIX)) { SET_METHODS.add(methodName); } } // 初始化 EXECUTE_METHODS methods Statement.class.getMethods(); for (Method method : methods) { String methodName method.getName(); if (methodName.startsWith(EXECUTE_METHOD_PREFIX) !executeQuery.equals(methodName)) { EXECUTE_METHODS.add(methodName); } } } /** * Log 对象 */ private final Log statementLog; /** * 查询层级 */ protected final int queryStack; /** * Constructor * * param log 日志对象 * param queryStack 查询层级 */ public BaseJdbcLogger(Log log, int queryStack) { this.statementLog log; if (queryStack 0) { this.queryStack 1; } else { this.queryStack queryStack; } } Override public boolean isDebugEnabled() { return statementLog.isDebugEnabled(); } Override public boolean isTraceEnabled() { return statementLog.isTraceEnabled(); } Override public void error(String s, Throwable e) { statementLog.error(s, e); } Override public void error(String s) { statementLog.error(s); } Override public void debug(String s) { statementLog.debug(s); } Override public void trace(String s) { statementLog.trace(s); } Override public void warn(String s) { statementLog.warn(s); } }SET_METHODS静态属性统计java.sql.PreparedStatement所有set方法名的集合。即所有设置 SQL 参数的方法的集合。EXECUTE_METHODS静态属性统计java.sql.Statement所有execute方法名的集合。即所有执行 SQL 语句的方法的集合。statementLog属性Log 对象。queryStack属性查询层级。该参数目前唯一使用的地方在#debug(String text)方法中代码如下// BaseJdbcLogger.java Override public void debug(String text) { // 1 如果是 debug 开启并且非嵌套查询才打印 if (statementLog.isDebugEnabled()) { statementLog.debug(prefix(text)); } } protected String prefix(String text) { StringBuilder builder new StringBuilder(); for (int i 0; i queryStack * 2; i) { // 2 使用 queryStack * 2 作为空格相当于是缩进 builder.append( ); } builder.append(text); return builder.toString(); }1处如果是 debug 开启并且非嵌套查询才打印日志。2处使用queryStack * 2作为空格相当于是缩进。4.2 ConnectionLoggerorg.apache.ibatis.logging.jdbc.ConnectionLogger继承 BaseJdbcLogger 抽象类Connection 日志增强类。4.2.1 构造方法/** * Connection 对象的代理 */ private final Connection connection; private ConnectionLogger(Connection conn, Log statementLog, int queryStack) { super(statementLog, queryStack); this.connection conn; }4.2.2 newInstancepublic static Connection newInstance(Connection conn, Log statementLog, int queryStack) { // 创建 InvocationHandler 对象 InvocationHandler handler new ConnectionLogger(conn, statementLog, queryStack); ClassLoader cl Connection.class.getClassLoader(); // 创建 Connection 代理 return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler); }创建 Connection 的代理对象。其中InvocationHandler 参数是 ConnectionLogger 对象。4.2.3 invokeOverride public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { // 如果调用的是 Object 的方法直接调用不做任何增强 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } // 如果调用的是 prepareStatement 方法则创建 PrepareStatement 的代理对象并进行增强 if (prepareStatement.equals(method.getName())) { if (isDebugEnabled()) { debug( Preparing: removeBreakingWhitespace((String) params[0]), true); } // 创建 PrepareStatement 对象 PreparedStatement stmt (PreparedStatement) method.invoke(connection, params); // 创建 PrepareStatement 的代理对象 stmt PreparedStatementLogger.newInstance(stmt, statementLog, queryStack); return stmt; } // 如果调用的是 prepareCall 方法则创建 CallableStatement 的代理对象并进行增强 else if (prepareCall.equals(method.getName())) { if (isDebugEnabled()) { debug( Preparing: removeBreakingWhitespace((String) params[0]), true); } // 创建 CallableStatement 对象 PreparedStatement stmt (PreparedStatement) method.invoke(connection, params); // 创建 CallableStatement 的代理对象 stmt PreparedStatementLogger.newInstance(stmt, statementLog, queryStack); return stmt; } // 如果调用的是 createStatement 方法则创建 Statement 的代理对象并进行增强 else if (createStatement.equals(method.getName())) { // 创建 Statement 对象 Statement stmt (Statement) method.invoke(connection, params); // 创建 Statement 的代理对象 stmt StatementLogger.newInstance(stmt, statementLog, queryStack); return stmt; } else { return method.invoke(connection, params); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }可以增强的方法有#prepareStatement(...)、#prepareCall(...)、#createStatement(...)方法分别创建对应的 PreparedStatement、CallableStatement、Statement 的代理对象。另外#removeBreakingWhitespace(String original)方法负责去除 SQL 语句中多余的换行和空格。代码如下// BaseJdbcLogger.java public static String removeBreakingWhitespace(String original) { StringTokenizer whitespaceStripper new StringTokenizer(original); StringBuilder builder new StringBuilder(); while (whitespaceStripper.hasMoreTokens()) { builder.append(whitespaceStripper.nextToken()); builder.append( ); } return builder.toString(); }4.3 PreparedStatementLoggerorg.apache.ibatis.logging.jdbc.PreparedStatementLogger继承 BaseJdbcLogger 抽象类PreparedStatement 日志增强类。4.3.1 构造方法/** * PreparedStatement 对象的代理 */ private final PreparedStatement statement; private PreparedStatementLogger(PreparedStatement stmt, Log statementLog, int queryStack) { super(statementLog, queryStack); this.statement stmt; }4.3.2 newInstancepublic static PreparedStatement newInstance(PreparedStatement stmt, Log statementLog, int queryStack) { // 创建 InvocationHandler 对象 InvocationHandler handler new PreparedStatementLogger(stmt, statementLog, queryStack); ClassLoader cl PreparedStatement.class.getClassLoader(); // 创建 PreparedStatement 代理对象 return (PreparedStatement) Proxy.newProxyInstance(cl, new Class[]{PreparedStatement.class, CallableStatement.class}, handler); }创建 PreparedStatement 的代理对象。其中InvocationHandler 参数是 PreparedStatementLogger 对象。另外我们可以看到handler参数还适配了java.sql.CallableStatement类。也就意味着PreparedStatementLogger 也可以增强 CallableStatement 的方法。4.3.3 invokeOverride public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { // 如果调用的是 Object 的方法直接调用不做任何增强 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } // 如果调用的是 execute 相关的方法 if (EXECUTE_METHODS.contains(method.getName())) { if (isDebugEnabled()) { debug(Parameters: getParameterValueString(), true); // 1 打印参数 } // 2 清空 columnMap、columnNames、columnValues clearColumnInfo(); // 3 执行方法 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); } } // 如果调用的是 set 相关的方法 else if (SET_METHODS.contains(method.getName())) { // 4 设置参数 if (setNull.equals(method.getName())) { setColumn(params[0], null); } else { setColumn(params[0], params[1]); } return method.invoke(statement, params); } // 如果调用的是 getResultSet 方法 else if (getResultSet.equals(method.getName())) { // 3 执行方法 ResultSet rs (ResultSet) method.invoke(statement, params); return rs null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack); } // 如果调用的是 getUpdateCount 方法 else if (getUpdateCount.equals(method.getName())) { // 3 执行方法 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); } }1处调用#getParameterValueString()方法获得参数的值进行打印。代码如下// PreparedStatementLogger.java private String getParameterValueString() { ListObject typeList new ArrayList(columnValues.size()); ListObject valueList new ArrayList(columnValues.size()); // 遍历 columnValues 数组 for (int i 0, n columnValues.size(); i n; i) { Object value columnValues.get(i); // 非空 if (value null) { valueList.add(null); typeList.add(null); // 非空 } else { valueList.add(value); typeList.add(columnTypes.get(i).getSimpleName()); } } // 拼接参数
返回列表