mybatis 日志源码

核心类

  • org.apache.ibatis.logging.Log
  • org.apache.ibatis.logging.LogFactory
  • 多个日志实现
    • org.apache.ibatis.logging.log4j2.Log4j2Impl
    • org.apache.ibatis.logging.slf4j.Slf4jLocationAwareLoggerImpl

源码流程

  • mybatis 提供了一个日志接口,内容如下.
  1. /**
  2. * mybatis 的日志接口,提供日志级别
  3. * <ol>
  4. * <li>error</li>
  5. * <li>debug</li>
  6. * <li>trace</li>
  7. * <li>warn</li>
  8. * </ol>
  9. * <p>通过自己定义的接口来实现各大日志框架的内容达到高可用</p>
  10. * @author Clinton Begin
  11. */
  12. public interface Log {
  13. boolean isDebugEnabled();
  14. boolean isTraceEnabled();
  15. void error(String s, Throwable e);
  16. void error(String s);
  17. void debug(String s);
  18. void trace(String s);
  19. void warn(String s);
  20. }
  • 有了日志接口必然有实现类, mybatis 有log4j2slf4j 等日志的相关实现 , 下面是Slf4jImpl的代码,其他代码也是一样的模式进行初始化就不再重复贴代码了.
  1. public class Slf4jImpl implements Log {
  2. private Log log;
  3. /**
  4. * 创建日志实例
  5. * @param clazz
  6. */
  7. public Slf4jImpl(String clazz) {
  8. Logger logger = LoggerFactory.getLogger(clazz);
  9. if (logger instanceof LocationAwareLogger) {
  10. try {
  11. // check for slf4j >= 1.6 method signature
  12. logger.getClass().getMethod("log", Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class);
  13. log = new Slf4jLocationAwareLoggerImpl((LocationAwareLogger) logger);
  14. return;
  15. } catch (SecurityException | NoSuchMethodException e) {
  16. // fail-back to Slf4jLoggerImpl
  17. }
  18. }
  19. // Logger is not LocationAwareLogger or slf4j version < 1.6
  20. log = new Slf4jLoggerImpl(logger);
  21. }
  22. @Override
  23. public boolean isDebugEnabled() {
  24. return log.isDebugEnabled();
  25. }
  26. @Override
  27. public boolean isTraceEnabled() {
  28. return log.isTraceEnabled();
  29. }
  30. @Override
  31. public void error(String s, Throwable e) {
  32. log.error(s, e);
  33. }
  34. @Override
  35. public void error(String s) {
  36. log.error(s);
  37. }
  38. @Override
  39. public void debug(String s) {
  40. log.debug(s);
  41. }
  42. @Override
  43. public void trace(String s) {
  44. log.trace(s);
  45. }
  46. @Override
  47. public void warn(String s) {
  48. log.warn(s);
  49. }
  50. }
  • 通过上述方法来达到统一接口多个实现,这个在开发中也经常使用.多日志的实现方法有了还缺一个创建方法,创建方法由org.apache.ibatis.logging.LogFactory提供
  1. /**
  2. * <p>日志工厂,实现内容:</p>
  3. * <ol>
  4. * <li>org.slf4j.Logger 日志框架 slf4j</li>
  5. * <li>org.apache.commons.logging.Log 日志框架 apache</li>
  6. * <li>org.apache.logging.log4j.Logger 日志框架 log4j2</li>
  7. * <li>org.apache.log4j.Logger 日志框架 log4j </li>
  8. * <li>java.util.logging.Logger 日志框架,JDK的logger</li>
  9. *
  10. * </ol>
  11. * @author Clinton Begin
  12. * @author Eduardo Macarron
  13. */
  14. public final class LogFactory {
  15. /**
  16. * Marker to be used by logging implementations that support markers.
  17. */
  18. public static final String MARKER = "MYBATIS";
  19. private static Constructor<? extends Log> logConstructor;
  20. /**
  21. * 日志的实现类的具体选择
  22. */
  23. static {
  24. // slf4j 日志
  25. tryImplementation(LogFactory::useSlf4jLogging);
  26. // apache 日志
  27. tryImplementation(LogFactory::useCommonsLogging);
  28. // log4j2 日志
  29. tryImplementation(LogFactory::useLog4J2Logging);
  30. // log4 日志
  31. tryImplementation(LogFactory::useLog4JLogging);
  32. // JDK 日志
  33. tryImplementation(LogFactory::useJdkLogging);
  34. // 空 日志
  35. tryImplementation(LogFactory::useNoLogging);
  36. }
  37. /**
  38. * 私有化构造方法,这是一个单例
  39. */
  40. private LogFactory() {
  41. // disable construction
  42. }
  43. public static Log getLog(Class<?> aClass) {
  44. return getLog(aClass.getName());
  45. }
  46. public static Log getLog(String logger) {
  47. try {
  48. return logConstructor.newInstance(logger);
  49. } catch (Throwable t) {
  50. throw new LogException("Error creating logger for logger " + logger + ". Cause: " + t, t);
  51. }
  52. }
  53. public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
  54. setImplementation(clazz);
  55. }
  56. public static synchronized void useSlf4jLogging() {
  57. setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
  58. }
  59. public static synchronized void useCommonsLogging() {
  60. setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class);
  61. }
  62. public static synchronized void useLog4JLogging() {
  63. setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class);
  64. }
  65. public static synchronized void useLog4J2Logging() {
  66. setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class);
  67. }
  68. public static synchronized void useJdkLogging() {
  69. setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class);
  70. }
  71. public static synchronized void useStdOutLogging() {
  72. setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class);
  73. }
  74. public static synchronized void useNoLogging() {
  75. setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class);
  76. }
  77. /**
  78. * 选择具体的日志实现
  79. */
  80. private static void tryImplementation(Runnable runnable) {
  81. if (logConstructor == null) {
  82. try {
  83. // run()? 似乎违背了代码的语义, 看静态方法.静态方法多行同类型的操作我认为是一个多线程
  84. runnable.run();
  85. } catch (Throwable t) {
  86. // ignore
  87. }
  88. }
  89. }
  90. /**
  91. * 选择具体的日志实现
  92. */
  93. private static void setImplementation(Class<? extends Log> implClass) {
  94. try {
  95. Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
  96. Log log = candidate.newInstance(LogFactory.class.getName());
  97. if (log.isDebugEnabled()) {
  98. log.debug("Logging initialized using '" + implClass + "' adapter.");
  99. }
  100. logConstructor = candidate;
  101. } catch (Throwable t) {
  102. throw new LogException("Error setting Log implementation. Cause: " + t, t);
  103. }
  104. }
  105. }
  • LogFactory是一个单例对象,对外公开getLog方法在使用时直接private static final Log log = LogFactory.getLog(CglibProxyFactory.class);即可

  • org.apache.ibatis.session.Configuration 中可以看到下面这些注册方法

  1. // 日志实现类
  2. typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
  3. typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
  4. typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
  5. typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
  6. typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
  7. typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
  8. typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);