中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MyBatis源碼分析之日志logging的示例分析

發布時間:2021-08-30 11:45:13 來源:億速云 閱讀:153 作者:小新 欄目:編程語言

這篇文章將為大家詳細講解有關MyBatis源碼分析之日志logging的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

logging 配置加載

我們先從日志的配置加載開始閱讀, MyBatis 的各項配置的加載過程都可以從 XMLConfigBuilder 類中找到,我們定位到該類下的日志加載方法 loadCustomLogImpl:

private void loadCustomLogImpl(Properties props) {
 // 從 MyBatis 的 TypeAliasRegistry 中查找 logImpl 鍵所對應值的類對象
 // 這里 logImpl 對應的 value 值可以從 org.apache.ibatis.session.Configuration 的構造方法中找到
 // 注意 Log 類,這是 MyBatis 內部對日志對象的抽象
 Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));
 // 將查找到的 Class 對象設置到 Configuration 對象中
 configuration.setLogImpl(logImpl);
}

很簡單的一個方法,每行都有注釋,其中 configuration.setLogImpl() 里面調用了 LogFactory.useCustomLogging() ,這出現了新類 LogFactory 類,接下來我們就來聊聊這個類。

LogFactory

useCustomLogging()方法

LogFactory 是框架內部獲取 Log 對象的手段,通過它的名字也能看出來。它有如下幾類方法:

// 注意這個類型的方法都是同步方法
public synchronized static useXxxLogging(...);

public static Log getLog(...);

private static tryImplementation(Runnable);

private static setImplementation(Class);

剛剛我們看到被調用的方法 useCustomLogging() 方法,是用來設置內部使用的日志框架, MyBatis 自身已經適配了一些常見的日志框架,如 Slf4j 、 Commons Log 、 Log4j 等等。

useCustomLogging() 方法內部調用 setImplementation(Class) 方法,此方法代碼如下,功能簡單:

private static void setImplementation(Class<? extends Log> implClass) {
 try {
  // 獲取 Log實現類的構造方法,它只有一個字符串作為參數
  Constructor<? extends Log> candidate = implClass.getConstructor(String.class);

  // 創建一個 Log 對象,打印 debug 日志
  Log log = candidate.newInstance(LogFactory.class.getName());
  if (log.isDebugEnabled()) {
   log.debug("Logging initialized using '" + implClass + "' adapter.");
  }

  // ...
  // 把 candidate 對象設置到 LogFactory 的靜態變量 logConstructor,這個靜態變量在 getLog() 方法
  // 中被用到
  logConstructor = candidate;
 } catch (Throwable t) {
  throw new LogException("Error setting Log implementation. Cause: " + t, t);
 }
}

Log 接口

剛剛我們接觸到了 Log 這個類,它是一個接口,是 MyBatis 內部使用的日志對象的抽象,它是為了兼容市面上各種各樣的日志框架,使用了適配器模式,通過 Log 接口來連接 MyBatis 和其他日志框架,通過實現 Log 接口連著 MyBatis 和需要適配的日志框架。

Log 接口代碼如下,先試著發現該接口與其他常見的日志接口的區別:

public interface Log {

 boolean isDebugEnabled();

 boolean isTraceEnabled();

 void error(String s, Throwable e);

 void error(String s);

 void debug(String s);

 void trace(String s);

 void warn(String s);

}

可有發現?Log 接口缺少了 info 級別的日志輸出方法,個人猜測應該是 MyBatis 內部不需要 info 級別的日志輸出,畢竟 Log 接口設計之初就是為了內部使用,而框架使用者是不會采用 MyBatis 的日志作為系統的日志。注意一點: 實現了 Log 接口的類必須擁有一個參數只有一個字符串的構造方法 ,MyBatis 就是通過這個構造方法創建日志對象的。

MyBatis 適配了許多常見的日志框架,這里就單單介紹 Log4jImpl 類,它代碼非常簡單:

public class Log4jImpl implements Log {

 private static final String FQCN = Log4jImpl.class.getName();

 // 這里包裝了 Log4j 框架的日志對象,從而實現適配
 private final Logger log;

 public Log4jImpl(String clazz) {
 log = Logger.getLogger(clazz);
 }

 @Override
 public boolean isDebugEnabled() {
 return log.isDebugEnabled();
 }

 @Override
 public boolean isTraceEnabled() {
 return log.isTraceEnabled();
 }

 @Override
 public void error(String s, Throwable e) {
 log.log(FQCN, Level.ERROR, s, e);
 }

 @Override
 public void error(String s) {
 log.log(FQCN, Level.ERROR, s, null);
 }

 @Override
 public void debug(String s) {
 log.log(FQCN, Level.DEBUG, s, null);
 }

 @Override
 public void trace(String s) {
 log.log(FQCN, Level.TRACE, s, null);
 }

 @Override
 public void warn(String s) {
 log.log(FQCN, Level.WARN, s, null);
 }

}

tryImplementation() 方法

LogFactory 類再介紹一下被靜態代碼塊使用的方法 tryImplementation(Runnable) 。靜態代碼塊代碼如下:

static {
 // 依次執行如下代碼,當沒有該類會拋 ClassNotFoundException ,然后繼續執行
 tryImplementation(LogFactory::useSlf4jLogging);
 tryImplementation(LogFactory::useCommonsLogging);
 tryImplementation(LogFactory::useLog4J2Logging);
 tryImplementation(LogFactory::useLog4JLogging);
 tryImplementation(LogFactory::useJdkLogging);
 tryImplementation(LogFactory::useNoLogging);
}

這個方法有點迷惑性,因為它使用 Runnable 接口作為參數,而 useXxxLOgging() 方法又是同步方法,很容易聯想到多線程,實際上這里并沒有, Runnable 接口不結合 Thread 類使用它就是一個普通的函數接口。除去這些就沒什么了,不過是調用了 Runnable 的 run() 方法而已。

getLog() 方法

getLog() 沒什么多說的,就是通過反射創建 Log 接口實現類,這里沒有使用到緩存,每次調用都是創建一個新的對象。

jdbc 包

這個包與其他包有些不同,它的職能是為各個階段的流程提供日志打印,該包一共就五個類,它們的關系如下:

MyBatis源碼分析之日志logging的示例分析

除了 BaseJdbcLogger 類其他類都實現了 InvocationHandler 接口,這個接口是 JDK 提供的動態代理接口,所以顯而易見可以知道它們就是通過代理在各個階段打印相應的日志。

以下為 BaseJdbcLogger 類的部分說明:

  • SET_METHODS:靜態字段,記錄 PreparedStatement 中 set 開頭的的方法名

  • EXECUTE_METHODS:靜態字段,記錄 SQL 執行的方法名

  • columnXxx:實例字段,記錄 SQL 參數信息

  • statementLog:日志對象

  • queryStack:查詢棧數

  • getParameterValueString():將 SQL 參數轉為一個字符串

  • removeBreakingWhitespace():移除 SQL 中多余的空白字符

  • prefix():獲取前綴 ==>/<==

而其余四個類都是簡單的邏輯:判斷執行的方法是否為指定方法,然后打印相應的日志。

關于“MyBatis源碼分析之日志logging的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

稷山县| 桑日县| 安阳市| 丹棱县| 临猗县| 彭阳县| 安新县| 晋州市| 麦盖提县| 红河县| 个旧市| 延津县| 勃利县| 井陉县| 汤阴县| 新巴尔虎右旗| 锦屏县| 顺昌县| 定日县| 玉屏| 湖北省| 靖边县| 建德市| 西昌市| 永靖县| 玉树县| 安多县| 曲松县| 炉霍县| 黔江区| 丰都县| 庆云县| 霍山县| 平泉县| 察哈| 六盘水市| 安乡县| 江西省| 宜兰市| 岳池县| 台南县|