1. 程式人生 > >淺談mybatis的日誌適配模式

淺談mybatis的日誌適配模式

開發十年,就只剩下這套架構體系了! >>>   

Java開發中經常用到的日誌框架有很多,Log4j、Log4j2、slf4j等等,Mybatis定義了一套統一的日誌介面供上層使用,併為上述常用的日誌框架提供了相應的介面卡。有關介面卡模式例子可以參考 設計模式整理

介面卡模式中有介面適配和委託適配兩種,當然我們可以把他們統一成又有介面又有委託,而不使用抽象類。

首先Mybatis中有一個日誌框架的介面,這個介面可能代表以上的各種日誌框架。

package org.apache.ibatis.logging;

public interface Log {
    boolean isDebugEnabled();

    boolean isTraceEnabled();

    void error(String var1, Throwable var2);

    void error(String var1);

    void debug(String var1);

    void trace(String var1);

    void warn(String var1);
}

以Slf4j為例來看它的介面卡,這是一個典型的委託介面卡,委託了Slf4j本身的物件,以及對該物件的呼叫。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.logging.slf4j;

import org.apache.ibatis.logging.Log;
import org.slf4j.Logger;

class Slf4jLoggerImpl implements 
Log { private final Logger log; public Slf4jLoggerImpl(Logger logger) { this.log = logger; } public boolean isDebugEnabled() { return this.log.isDebugEnabled(); } public boolean isTraceEnabled() { return this.log.isTraceEnabled(); } public void error(String s, Throwable e) { this.log.error(s, e); } public void error(String s) { this.log.error(s); } public void debug(String s) { this.log.debug(s); } public void trace(String s) { this.log.trace(s); } public void warn(String s) { this.log.warn(s); } }

呼叫以上介面卡,並初始化一個真正的Slf4j的例項來使用該介面卡。可以看成是以上介面卡的一個延伸,主要是為了轉化成一個String型別的單參構造器,方便統一呼叫。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.logging.slf4j;

import org.apache.ibatis.logging.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.spi.LocationAwareLogger;

public class Slf4jImpl implements Log {
    private Log log;

    public Slf4jImpl(String clazz) {
        Logger logger = LoggerFactory.getLogger(clazz);
        if(logger instanceof LocationAwareLogger) {
            try {
                logger.getClass().getMethod("log", new Class[]{Marker.class, String.class, Integer.TYPE, String.class, Object[].class, Throwable.class});
                this.log = new Slf4jLocationAwareLoggerImpl((LocationAwareLogger)logger);
                return;
            } catch (SecurityException var4) {
                ;
            } catch (NoSuchMethodException var5) {
                ;
            }
        }

        this.log = new Slf4jLoggerImpl(logger);
    }

    public boolean isDebugEnabled() {
        return this.log.isDebugEnabled();
    }

    public boolean isTraceEnabled() {
        return this.log.isTraceEnabled();
    }

    public void error(String s, Throwable e) {
        this.log.error(s, e);
    }

    public void error(String s) {
        this.log.error(s);
    }

    public void debug(String s) {
        this.log.debug(s);
    }

    public void trace(String s) {
        this.log.trace(s);
    }

    public void warn(String s) {
        this.log.warn(s);
    }
}

Mybatis日誌工廠使用這些介面卡,從它的靜態程式碼塊來看,是啟用執行緒任務來嘗試載入各種日誌框架。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.logging;

import java.lang.reflect.Constructor;
import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl;
import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl;
import org.apache.ibatis.logging.log4j.Log4jImpl;
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
import org.apache.ibatis.logging.nologging.NoLoggingImpl;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.logging.stdout.StdOutImpl;

public final class LogFactory {
    public static final String MARKER = "MYBATIS";
    //日誌框架介面的構造器
    private static Constructor<? extends Log> logConstructor;
    //日誌工廠的私有構造器,即它不能被例項化
    private LogFactory() {
    }

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

    public static Log getLog(String logger) {
        try {
            return (Log)logConstructor.newInstance(new Object[]{logger});
        } catch (Throwable var2) {
            throw new LogException("Error creating logger for logger " + logger + ".  Cause: " + var2, var2);
        }
    }

    public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
        setImplementation(clazz);
    }

    public static synchronized void useSlf4jLogging() {
        setImplementation(Slf4jImpl.class);
    }

    public static synchronized void useCommonsLogging() {
        setImplementation(JakartaCommonsLoggingImpl.class);
    }

    public static synchronized void useLog4JLogging() {
        setImplementation(Log4jImpl.class);
    }

    public static synchronized void useLog4J2Logging() {
        setImplementation(Log4j2Impl.class);
    }

    public static synchronized void useJdkLogging() {
        setImplementation(Jdk14LoggingImpl.class);
    }

    public static synchronized void useStdOutLogging() {
        setImplementation(StdOutImpl.class);
    }

    public static synchronized void useNoLogging() {
        setImplementation(NoLoggingImpl.class);
    }
    //如果前面的日誌框架沒有被載入,則載入後面的
    private static void tryImplementation(Runnable runnable) {
        if(logConstructor == null) {
            try {
                runnable.run();
            } catch (Throwable var2) {
                ;
            }
        }

    }
    //例項化介面卡,並記錄該介面卡的構造器是否為空
    private static void setImplementation(Class<? extends Log> implClass) {
        try {
            //獲取指定介面卡的構造方法,因為這些介面卡的構造器都是一個String型別的單參構造器
            Constructor<? extends Log> candidate = implClass.getConstructor(new Class[]{String.class});
            //使用構造器來例項化指定的介面卡
            Log log = (Log)candidate.newInstance(new Object[]{LogFactory.class.getName()});
            if(log.isDebugEnabled()) {
                log.debug("Logging initialized using '" + implClass + "' adapter.");
            }
            //初始化日誌工廠的日誌框架構造器欄位
            logConstructor = candidate;
        } catch (Throwable var3) {
            throw new LogException("Error setting Log implementation.  Cause: " + var3, var3);
        }
    }
    //根據各種日誌框架,來嘗試載入,依次順序為Slf4j,Commons,Log4j2,Log4j,jdk,useNo。直到載入成功一個為止,後面的將不再載入。
    static {
        tryImplementation(new Runnable() {
            public void run() {
                LogFactory.useSlf4jLogging();
            }
        });
        tryImplementation(new Runnable() {
            public void run() {
                LogFactory.useCommonsLogging();
            }
        });
        tryImplementation(new Runnable() {
            public void run() {
                LogFactory.useLog4J2Logging();
            }
        });
        tryImplementation(new Runnable() {
            public void run() {
                LogFactory.useLog4JLogging();
            }
        });
        tryImplementation(new Runnable() {
            public void run() {
                LogFactory.useJdkLogging();
            }
        });
        tryImplementation(new Runnable() {
            public void run() {
                LogFactory.useNoLogging();
            }
        });

            
           

相關推薦

mybatis日誌模式

開發十年,就只剩下這套架構體系了! >>>   

移動端大法

前言 前端程式碼的編寫永遠逃不過“相容”二詞,從前PC時代,因為IE的傲嬌,導致程式猿們一直在相容IE的道路上掙扎,如今移動裝置的普及,彷彿讓我們看到了希望,彷彿馬上就要擺脫IE了,可是!一波還未平息,一波又來侵襲~移動端確實不用考慮IE了,各種CSS新特性也用的爽到飛起,但一座大山壓了過來,那就是解析度的

android 螢幕中 dp和sp的區別

歡迎轉載 轉載註明出處 關於dp和sp的具體區別 看網上文章少有深入涉及 介於一次面試被問到:sp和dp的關係是什麼?例如一個控制元件寬度為 15dp 或者 15sp 在大部分情況下是一樣的,那什麼情況下不同? 找了半天木有這類文章,最後蒐集各種資源,在這

Mybatis中的 ${ } 和 #{ }的區別

mybatis sql註入 語句 nbsp 之前 com pre 預編譯 sql 語句 一、舉例說明 1 select * from user where name = "dato"; 2 3 select * from user where name = #

dubbo之日誌及訪問日誌

訪問日誌 DDU ring toc accesslog span rate slf4j spa 日誌適配 自 2.2.1 開始,dubbo 開始內置 log4j、slf4j、jcl、jdk 這些日誌框架的適配 1,也可以通過以下方式顯示配置日誌輸出策略: 命令行

mybatis連接原理

屬於 完成 string vat 動態 template ger 滿足 apt 眾所周知數據庫連接的過程,但是最近面試的人(菜面菜),都說用的SSM框架,但是我問了一下,mybatis是怎麽連接上mysql的,基本上都會說:配置好的,直接用了,今天我來拋磚引玉

架構、框架、模式、模組、元件、外掛、控制元件、中介軟體

軟體開發中,你常常會聽到技術架構、開發框架、設計模式、程式碼模組、中間層(件)、可插拔元件等等計算機行業的專有名詞。這些名詞和我們的開發工作息息相關,如果你想要在開發領域做的更好、走的更遠,你必須要對這些專有名詞有一個大概的瞭解。 1、架構 架構也成稱為軟體體系結構。簡單地說就是一種設計

設計模式---模式

設計模式---適配模式 介紹 什麼是適配模式:將一個類的介面轉換成客戶希望的另一個介面。Adapter模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。 實現  介面卡模式有兩種:類介面卡、物件介面卡、介面介面卡 類介面卡模式: 原理

自己對Java代理模式的理解--即為什麼要用&怎麼用

                首先,國際慣例,上Java代理模式的定義:                        Java代理模式:對其他物件提供一種代理以控制對這個物件的訪問。 定義很簡單,就一句話,怎麼去理解,不急,先聽一個小故事:              

android的MVP設計模式之記憶體洩露問題

我上次寫了淺談mvp,經過一段時間的思考,發現我忽略了一個問題 記憶體洩露問題。 因為Presenter中持有View介面物件,這個介面物件實際為MainActivity.this,Modle中也同時擁有Presenter物件例項,當MainActivi

以C/C++語法二十三種設計模式(一)——工廠模式(Factory Method)

0.寫在前面 在軟體開發過程中,為了提高開發效率、增強軟體執行的穩定性,降低後期專案維護的成本,我們志在追求更加高效、簡單的設計思路來引領我們的專案產品,在經過不斷的探索與總結的過程中,我們最常用的設計模式有23中,總體分為三大類,即建立型模式、結構型模式和行為型模式,具體如下:

springMVC中的設計模式(5)——組合模式

相信大家在使用springMVC的時候,都或多或少需要對它進行配置,不管使用xml的方式還是Java註解的方式。今天我們就從springMVC的配置上,談一談其中一個很重要的設計模式:組合模式。 定義 慣例我們先來看一看組合模式的定義:組合模式,將物件組合成

Spring Mvc的設計模式

Spring Mvc這個框架給我的第一感覺是大大的優化了web層,特別是配合註解的形式,對於比較中小型的網站,我個人覺得還是比較適合的。 Spring Mvc的底層實現核心是基於Aop的,DispatcherServlet作為攔截器的核心,負責接受所有的攔截請求,這也是Ao

Mybatis中session的一級快取的實現原理

最近由於受工作中業務需要和現有工程中dao層非orm思想的影響,覺得在有些業務場景下,並不一定非要去使用ORM框架,畢竟寫大量的實體類也是一件麻煩的事,於是著手編寫一個非ORM框架。初步完成後,底層的session並沒能像mybatis那樣能支援session的一級快取

MyBatis的工作原理

瞭解MyBatis工作原理先了解這幾個類的作用: Configuration           MyBatis所有的配置資訊都儲存在Configuration物件之中,配置檔案中的大部分配置都會儲存到該類中 SqlSession               作為MyBa

Android中的MVVM模式

大家好啊,我是kele。眾所周知,Android的設計模式主要有三個:MVC,MVP,MVVM。今天主要來談一下MVVM模式,簡單說明它的好處以及它和MVP在實現方面的區別。 DataBinding android { ....

springMVC中的設計模式(1)——責任鏈模式

最近終於閒了下來,準備自己記錄些東西。網上關於springMVC的資料很多,但關於設計模式的還有限,我就想把springMVC原始碼中的設計模式抽出來做成一個系列,簡單的談一下其中的實現原理,作為一種學習分享,以後有更深的感悟也會更新。 先從一張圖對整個spr

java 23種設計模式之模板方法模式(Template )

模板方法模式:模板方法模式是類的行為模式的一種,符合開閉原則(對擴充套件開放,對修改關閉)。父類提取子類公共方法,並提供若干抽象方法供子類實現,以減少子類中的重複程式碼,並提高可複用性。示例:1.建立一個父類bird,每天只有吃和睡才能生活,但是必須要先進行吃,然後再進行睡:

iOS日誌收集系統

在應用開發中為了給使用者更好操作體驗與精準資訊的展示,往往會收集一些使用者行為資訊,比如應用中使用者習慣的操作流程,相關頁面訪問次數,使用者個人資訊等等。大多數應用會整合第三方廠商提供的服務來統計這些資料,當然這樣做帶來的好處就是不用花費時間來寫相關日誌收集的功

Mybatis通用Mapper使用方法

對單表進行增刪改查是專案中不可避免的需求,Mybatis的通用Mapper外掛使這些操作變得簡單新增maven依賴在對應工程的pom.xml檔案中新增<dependency> <groupId>javax.persistence</groupId> <