Spring + MyBaits 日志初始化兩遍的問題


偶然發現一個問題,記錄一下以備查詢。

問題:系統啟動時發現日志初始化了兩次

14:28:04.798 [main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
14:28:04.970 [main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.

相關環境文件

mybatis-config.xml片段:

<settings>
  <setting name="logImpl" value="SLF4J" />      <!-- 日志實現包 -->
</settings>

applicitionContext.xml片段:

<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="driverManagerDataSource" />
    <property name="configLocation" value="classpath:mybatis-config.xml" />
</bean>

 

既然是LogFactory打印的日志,先從LogFactory開始看,

public final class LogFactory {
private static Constructor<? extends Log> logConstructor;

  static {                   // 加載時按順序嘗試日志實現,這是第一條日志的輸出
    tryImplementation(new Runnable() {
      public void run() {
        useSlf4jLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useCommonsLogging();
      }
    });
  // 忽略部分代碼
    tryImplementation(new Runnable() {
      public void run() {
        useNoLogging();
      }
    });
  }

  private LogFactory() {
    // disable construction
  }

  public static Log getLog(Class<?> aClass) {
    return getLog(aClass.getName());
  }

  public static Log getLog(String logger) {
    try {
      return logConstructor.newInstance(new Object[] { 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 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) {   // 當加載日志實現成功一次后,這里logConstructor已經不為null
      try {
        runnable.run();
      } catch (Throwable t) {
        // ignore
      }
    }
  }

  private static void setImplementation(Class<? extends Log> implClass) {
    try {
      Constructor<? extends Log> candidate = implClass.getConstructor(new Class[] { String.class });
      Log log = candidate.newInstance(new Object[] { LogFactory.class.getName() });
      log.debug("Logging initialized using '" + implClass + "' adapter.");
      logConstructor = candidate;
    } catch (Throwable t) {
      throw new LogException("Error setting Log implementation.  Cause: " + t, t);
    }
  }
}

可以看出在spring容器啟動時,已經加載了一個“org.apache.ibatis.logging.slf4j.Slf4jImpl”;

 

那么第二條日志是什么時候輸出呢?

容器在構造SqlSessionFactoryBean時,需要mybatis-config.xml,因為有<setting name="logImpl" value="SLF4J" />這一條配置,

所以在解析到這一條時調用了org.apache.ibatis.session.Configuration這個類又執行了一次初始化,

順序SqlSessionFactoryBean -> SqlSessionFactoryBuilder -> XMLConfigBuilder -> Configuration

最終Configuration中:

  public void setLogImpl(Class<?> logImpl) {
    if (logImpl != null) {
      this.logImpl = (Class<? extends Log>) logImpl;
      LogFactory.useCustomLogging(this.logImpl);
    }
  }

由此也看明白了配置日志實現相當於手動執行org.apache.ibatis.logging.LogFactory.useSlf4jLogging()mybatis文檔中也寫到了:

如果要手動調用LogFactory.use***Logging()方法,請在調用所有其他MyBatis方法前調用它。另外,只有在相應日志實現存在 的前提下,調用對應的方法才是有意義的,否則MyBatis一概忽略。如你環境中並不存在Log4J,你卻調用了 相應的方法,MyBatis就會忽略這一調用,代之默認的查找順序查找日志實現。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM