- Author: HuiFer
- Description: 该文介绍 mybatis 日志相关源码
- 源码阅读工程: SourceHot-Mybatis
org.apache.ibatis.logging.Log
org.apache.ibatis.logging.LogFactory
- 多个日志实现
org.apache.ibatis.logging.log4j2.Log4j2Impl
org.apache.ibatis.logging.slf4j.Slf4jLocationAwareLoggerImpl
- ...
- mybatis 提供了一个日志接口,内容如下.
/** * mybatis 的日志接口,提供日志级别 * <ol> * <li>error</li> * <li>debug</li> * <li>trace</li> * <li>warn</li> * </ol> * <p>通过自己定义的接口来实现各大日志框架的内容达到高可用</p> * @author Clinton Begin */publicinterfaceLog { booleanisDebugEnabled(); booleanisTraceEnabled(); voiderror(Strings, Throwablee); voiderror(Strings); voiddebug(Strings); voidtrace(Strings); voidwarn(Strings); }
- 有了日志接口必然有实现类, mybatis 有
log4j2
、slf4j
等日志的相关实现 , 下面是Slf4jImpl
的代码,其他代码也是一样的模式进行初始化就不再重复贴代码了.
publicclassSlf4jImplimplementsLog { privateLoglog; /** * 创建日志实例 * @param clazz */publicSlf4jImpl(Stringclazz) { Loggerlogger = LoggerFactory.getLogger(clazz); if (loggerinstanceofLocationAwareLogger) { try { // check for slf4j >= 1.6 method signaturelogger.getClass().getMethod("log", Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class); log = newSlf4jLocationAwareLoggerImpl((LocationAwareLogger) logger); return; } catch (SecurityException | NoSuchMethodExceptione) { // fail-back to Slf4jLoggerImpl } } // Logger is not LocationAwareLogger or slf4j version < 1.6log = newSlf4jLoggerImpl(logger); } @OverridepublicbooleanisDebugEnabled() { returnlog.isDebugEnabled(); } @OverridepublicbooleanisTraceEnabled() { returnlog.isTraceEnabled(); } @Overridepublicvoiderror(Strings, Throwablee) { log.error(s, e); } @Overridepublicvoiderror(Strings) { log.error(s); } @Overridepublicvoiddebug(Strings) { log.debug(s); } @Overridepublicvoidtrace(Strings) { log.trace(s); } @Overridepublicvoidwarn(Strings) { log.warn(s); } }
- 通过上述方法来达到统一接口多个实现,这个在开发中也经常使用.多日志的实现方法有了还缺一个创建方法,创建方法由
org.apache.ibatis.logging.LogFactory
提供
/** * <p>日志工厂,实现内容:</p> * <ol> * <li>org.slf4j.Logger 日志框架 slf4j</li> * <li>org.apache.commons.logging.Log 日志框架 apache</li> * <li>org.apache.logging.log4j.Logger 日志框架 log4j2</li> * <li>org.apache.log4j.Logger 日志框架 log4j </li> * <li>java.util.logging.Logger 日志框架,JDK的logger</li> * * </ol> * @author Clinton Begin * @author Eduardo Macarron */publicfinalclassLogFactory { /** * Marker to be used by logging implementations that support markers. */publicstaticfinalStringMARKER = "MYBATIS"; privatestaticConstructor<? extendsLog> logConstructor; /** * 日志的实现类的具体选择 */static { // slf4j 日志tryImplementation(LogFactory::useSlf4jLogging); // apache 日志tryImplementation(LogFactory::useCommonsLogging); // log4j2 日志tryImplementation(LogFactory::useLog4J2Logging); // log4 日志tryImplementation(LogFactory::useLog4JLogging); // JDK 日志tryImplementation(LogFactory::useJdkLogging); // 空 日志tryImplementation(LogFactory::useNoLogging); } /** * 私有化构造方法,这是一个单例 */privateLogFactory() { // disable construction } publicstaticLoggetLog(Class<?> aClass) { returngetLog(aClass.getName()); } publicstaticLoggetLog(Stringlogger) { try { returnlogConstructor.newInstance(logger); } catch (Throwablet) { thrownewLogException("Error creating logger for logger " + logger + ". Cause: " + t, t); } } publicstaticsynchronizedvoiduseCustomLogging(Class<? extendsLog> clazz) { setImplementation(clazz); } publicstaticsynchronizedvoiduseSlf4jLogging() { setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class); } publicstaticsynchronizedvoiduseCommonsLogging() { setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class); } publicstaticsynchronizedvoiduseLog4JLogging() { setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class); } publicstaticsynchronizedvoiduseLog4J2Logging() { setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class); } publicstaticsynchronizedvoiduseJdkLogging() { setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class); } publicstaticsynchronizedvoiduseStdOutLogging() { setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class); } publicstaticsynchronizedvoiduseNoLogging() { setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class); } /** * 选择具体的日志实现 */privatestaticvoidtryImplementation(Runnablerunnable) { if (logConstructor == null) { try { // run()? 似乎违背了代码的语义, 看静态方法.静态方法多行同类型的操作我认为是一个多线程runnable.run(); } catch (Throwablet) { // ignore } } } /** * 选择具体的日志实现 */privatestaticvoidsetImplementation(Class<? extendsLog> implClass) { try { Constructor<? extendsLog> candidate = implClass.getConstructor(String.class); Loglog = candidate.newInstance(LogFactory.class.getName()); if (log.isDebugEnabled()) { log.debug("Logging initialized using '" + implClass + "' adapter."); } logConstructor = candidate; } catch (Throwablet) { thrownewLogException("Error setting Log implementation. Cause: " + t, t); } } }
LogFactory
是一个单例对象,对外公开getLog
方法在使用时直接private static final Log log = LogFactory.getLog(CglibProxyFactory.class);
即可在
org.apache.ibatis.session.Configuration
中可以看到下面这些注册方法
// 日志实现类typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class); typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class); typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class); typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class); typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class); typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class); typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);