首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

MyBatis 啟動無限打印「Logging initialized」日誌:根因定位與徹底解決

     編輯:Java 相關知識

現象描述

項目啟動時控制台疯狂輸出:

Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
... (無限循環)

**關鍵特徵**:僅在 Spring 整合 MyBatis 時發生,純 MyBatis 不會出現。

根因分析

1. 直接原因:Mapper XML 解析失敗

  • XML 文件語法錯誤 (少標簽、屬性錯誤、特殊字符未轉義)
  • XML 文件編碼不一致 (文件實際 UTF-8 但聲明 GBK,或反過來)
  • XML 文件開頭有隱形字符 (BOM、空格、雜質字符如示例中的 emplo)

2. 深層原因:Spring 異常吞噬機制導致無限重試

當 SqlSessionFactoryBean 初始化失敗時,Spring 的 Bean 創建流程會捕獲異常並嘗試重試/繼續,觸發 MyBatis 重新初始化日誌適配器,形成死循環。

快速定位錯誤 XML 的兩大絕招

絕招一:斷點大法 (最精準)

  1. 打開 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
  2. 定位 autowireByType 方法 (~第 1200 行)
  3. 找到 catch (BeansException ex) 塊:
catch (BeansException ex) {
    throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
    // ↑ 在這行打斷點 (Throw 彈出時自動暫停)
}
  1. Debug 啟動項目,斷點命中時查看 ex 異常詳情
  2. 異常信息示例:
org.springframework.core.NestedIOException:
Failed to parse mapping resource: 'file [.../EmployeeMapper.xml]'
nested exception is org.apache.ibatis.builder.BuilderException:
Error creating document instance.
Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.
  1. 異常明確指向 EmployeeMapper.xml 第 1 行第 1 列有非法內容

絕招二:更早攔截點 (覆蓋面更廣)

  1. 打開 org.springframework.beans.factory.support.AbstractBeanFactory
  2. 定位 getTypeForFactoryBean 方法
  3. 找到 catch (BeanCreationException ex):
catch (BeanCreationException ex) {
    if (logger.isDebugEnabled()) {
        logger.debug("Ignoring bean creation exception on FactoryBean type check: " + ex);
    }
    onSuppressedException(ex); // 這裡吞了異常!
    return null;
}
  1. 在 onSuppressedException(ex) 或 return null 打斷點
  2. 此處能捕獲更早期的 Bean 創建異常,堆棧更豐富

實戰案例:隱形字符導致 XML 解析失敗

打開報錯的 EmployeeMapper.xml,發現文件開頭多出 emplo 字符:

emplo<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper ...>
...

**原因不明** (可能誤粘貼、編碼轉換殘留、IDE 緩存)。刪除雜質字符,保存,重啟 → **問題解決**。

為什麼只看到無限日誌不見真實異常?

Spring 在 AbstractBeanFactory.getTypeForFactoryBean 中捕獲 BeanCreationException 後,僅打印 Debug 日誌並調用 onSuppressedException 吞噬異常,隨後返回 null 導致上層邏輯誤以為 Bean 類型未知,繼續嘗試初始化,觸發 MyBatis 重複初始化日誌適配器。

徹底解決方案清單

  1. 檢查所有 Mapper XML:
    • 文件編碼統一 UTF-8 (IDE 右下角確認)
    • 無 BOM 頭 (IDE 設置保存無 BOM)
    • 首行必須是 <?xml ...?>,前無任何字符
    • 標簽閉合正確,屬性引號匹配
    • 特殊字符 (<, >, &, ', ") 已轉義或用 CDATA
  2. 啟動日誌級別調整:log4j.logger.org.springframework=WARN 減少干擾,但**不解決根本問題**
  3. 升級 MyBatis-Spring 版本:新版本異常處理更健壯,可能避免無限重試
  4. 構建腳本驗證 XML:Maven 階段用 xml-maven-plugin 驗證 XML 格式,提前發現

總結

**「Logging initialized 無限打印 = Mapper XML 解析失敗 + Spring 異常吞噬重試」**。**核心解決路徑**:斷點 AbstractAutowireCapableBeanFactory.autowireByType 的 catch 塊 → 直接看到真實異常 → 定位具體 XML → 修復語法/編碼/隱形字符。此法百試百靈,比盲目排查配置文件高效百倍。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved