Mybatis源碼-日志模塊(1)

mybatis log模塊

??Mybatis的日志模塊的作用是為了讓mybatis在項(xiàng)目中被使用的時(shí)候衔彻,無(wú)論什么情況都能有一種日志實(shí)現(xiàn)讓mybatis可以正常的打日志且预。所以mybatis不能用單一的實(shí)現(xiàn)方式去打印日志。
不能像我們平常一樣用slf4j的LogFactory.getLogger(XXXX)一樣去用日志爵卒。因?yàn)樗赡茉跊]有Slf4j的項(xiàng)目里被使用。難道就不打日志了么?

??那mybatis怎么辦呢古毛?他就在各種輸出手段的外面再包一層統(tǒng)一的接口門面。然后哪個(gè)可以用就用哪個(gè)都许。也就是設(shè)計(jì)模式中的“適配器模式”稻薇。通過(guò)LogFactory和Log統(tǒng)一封裝底層不同實(shí)現(xiàn)的差異。在mybatis自己的代碼中胶征,記錄日志的常規(guī)用法就是LogFactory.getLog(XXX.class)

這里面的主要代碼集中實(shí)現(xiàn)在LogFactory中塞椎。對(duì)照注釋閱讀。

public final class LogFactory {

  /**
   * Marker to be used by logging implementations that support markers.
   */
  public static final String MARKER = "MYBATIS";

  private static Constructor<? extends Log> logConstructor;

  static {
    /**
     * 依次去嘗試設(shè)置LogFactory會(huì)用哪一種Log實(shí)現(xiàn)去做日志睛低。
     * 第一個(gè)成功的會(huì)塞入logConstructor案狠,用于后面創(chuàng)建mybatis的通用日志接口Logger
     * 最優(yōu)先的是slf4j。從上到下一次排列
     *
     * 這里有一個(gè)問(wèn)題是為什么每一種useXXX方法都是同步的呢暇昂?他們明明就在同一個(gè)static塊中被依次調(diào)用莺戒。
     * 后來(lái)仔細(xì)一想,是因?yàn)檫@些方法也可以在LogFactory的Class被初始化加載之后急波,在不用的地方被不同的線程調(diào)用从铲。
     * 從而動(dòng)態(tài)改變Log的具體實(shí)現(xiàn)者,如果這些方法不是synchronized的話澄暮,不同的線程對(duì)logConstructor就會(huì)出現(xiàn)可見性問(wèn)題名段。
     * 類似于單例懶加載雙重檢查鎖。
     */
    tryImplementation(LogFactory::useSlf4jLogging);
    tryImplementation(LogFactory::useCommonsLogging);
    tryImplementation(LogFactory::useLog4J2Logging);
    tryImplementation(LogFactory::useLog4JLogging);
    tryImplementation(LogFactory::useJdkLogging);
    tryImplementation(LogFactory::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(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);
  }
  //····省略一堆userXXLogging方法……

  //這里的邏輯一種是一種裝載緩存內(nèi)容的典型判斷泣懊,沒有就嘗試去裝載logConstructor
  private static void tryImplementation(Runnable runnable) {
    if (logConstructor == null) {
      try {
        runnable.run();
      } catch (Throwable t) {
        // ignore
      }
    }
  }
  //這里嘗試傳入的是實(shí)現(xiàn)了ibatis的Log適配器接口的實(shí)現(xiàn)類
  private static void setImplementation(Class<? extends Log> implClass) {
    try {
      //這些實(shí)現(xiàn)類都有一個(gè)string參數(shù)的構(gòu)造器伸辟,用于傳入logger的名字,
      //不過(guò)這一點(diǎn)并不是從語(yǔ)法上限制死的馍刮。而是mybatis對(duì)每一個(gè)實(shí)現(xiàn)都提供了這樣的constructor
      Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
      //用mybatis的LogFactory的名字創(chuàng)建一個(gè)mybatis的log接口信夫,具體的實(shí)現(xiàn)由被適配的具體實(shí)現(xiàn)決定
      Log log = candidate.newInstance(LogFactory.class.getName());
      //馬上就用了,打印的第一句就是卡啰,表明用了什么日志適配器實(shí)現(xiàn)
      if (log.isDebugEnabled()) {
        log.debug("Logging initialized using '" + implClass + "' adapter.");
      }
      //Log適配器的構(gòu)造器緩存下來(lái)静稻,用于后面創(chuàng)建其他日志
      logConstructor = candidate;
      //所以這個(gè)方法的核心作用就是,抽取我們的真正的日志適配器實(shí)現(xiàn)的constructor緩存起來(lái)匈辱,用于后面創(chuàng)建log
    } catch (Throwable t) {
      //注意這個(gè)方法其實(shí)會(huì)經(jīng)常拋錯(cuò)的振湾。因?yàn)橐玫讓拥膶?shí)現(xiàn)的前提是引入了這個(gè)實(shí)現(xiàn)的包。并且能用亡脸。
      // 當(dāng)不成功的時(shí)候押搪,通常就是缺了實(shí)現(xiàn)類树酪。比如第一個(gè)的Slf4j的logg實(shí)現(xiàn),如果沒有slff4j的jar大州,自然就失敗了续语。
      //所以在外面tryImplementation這個(gè)方法會(huì)抓住我們的初始化異常。并忽略它摧茴。設(shè)置失敗就算咯~嘗試其他的绵载。
      throw new LogException("Error setting Log implementation.  Cause: " + t, t);
    }
  }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市苛白,隨后出現(xiàn)的幾起案子娃豹,更是在濱河造成了極大的恐慌,老刑警劉巖购裙,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懂版,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡躏率,警方通過(guò)查閱死者的電腦和手機(jī)躯畴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)薇芝,“玉大人蓬抄,你說(shuō)我怎么就攤上這事『坏剑” “怎么了嚷缭?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)耍贾。 經(jīng)常有香客問(wèn)我阅爽,道長(zhǎng),這世上最難降的妖魔是什么荐开? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任付翁,我火速辦了婚禮,結(jié)果婚禮上晃听,老公的妹妹穿的比我還像新娘百侧。我一直安慰自己,他們只是感情好能扒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布佣渴。 她就那樣靜靜地躺著,像睡著了一般赫粥。 火紅的嫁衣襯著肌膚如雪观话。 梳的紋絲不亂的頭發(fā)上予借,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天越平,我揣著相機(jī)與錄音频蛔,去河邊找鬼。 笑死秦叛,一個(gè)胖子當(dāng)著我的面吹牛晦溪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挣跋,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼三圆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了避咆?” 一聲冷哼從身側(cè)響起舟肉,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎查库,沒想到半個(gè)月后路媚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡樊销,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年整慎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片围苫。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡裤园,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出剂府,到底是詐尸還是另有隱情拧揽,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布周循,位于F島的核電站强法,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏湾笛。R本人自食惡果不足惜饮怯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嚎研。 院中可真熱鬧蓖墅,春花似錦、人聲如沸临扮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)杆勇。三九已至贪壳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚜退,已是汗流浹背闰靴。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工彪笼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蚂且。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓配猫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親杏死。 傳聞我的和親對(duì)象是個(gè)殘疾皇子泵肄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容