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

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

問題:系統啓動時發現日誌初始化了兩次sql

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.

相關環境文件apache

mybatis-config.xml片斷:session

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

applicitionContext.xml片斷:mybatis

<!-- 配置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開始看,app

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」;ui

 

那麼第二條日誌是何時輸出呢?this

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

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

順序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就會忽略這一調用,代之默認的查找順序查找日誌實現。

相關文章
相關標籤/搜索