天天看點

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

目錄

一、主流的log技術名詞

1.1 log4j

1.2 JUL

1.3 JCL

1.4 SLF4J

1.4.1 綁定器

1.4.2 橋接器

1.5 log4j2

1.6 logback

1.7 simple-log

1.8 各種日志技術的關系和作用

二、spring日志技術分析

2.1 spring4日志技術實作

2.1 spring5日志技術實作

一、主流的log技術名詞

1.1 log4j

maven依賴:

<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.17</version>
</dependency>
           

可以不需要依賴第三方的技術,直接記錄日志,但是必須要有配置檔案。

使用:

// 引用的是log4j的Logger
import org.apache.log4j.Logger;
public class Log4j {
    public static void main(String[] args) {
        // 擷取log4j的Logger對象,後面的括号是設定日志對象的唯一辨別,可以自定義命名或目前類的Class
        Logger logger = Logger.getLogger(Log4j.class);
        logger.info("log4j");
    }
}
           

效果:

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

1.2 JUL

java自帶的一個日志記錄的技術,可以直接使用,不需要引用依賴包

使用:

// 這裡引用的是JUL包下的Logger
import java.util.logging.Logger;
/**
 * 使用JUL記錄日志不需要引用外部包,因為JUL是jdk自帶的
 *
 * 不使用配置檔案也可以使用
 */
public class JUL {
    public static void main(String[] args) {
        // JUL的Logger對象隻能為其設定字元串命名,不能使用Class作為其辨別
        Logger logger = Logger.getLogger("JUL");
        logger.info("jul");
    }
}
           

效果:

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

1.3 JCL

jakarta Commons LoggingImpl

maven依賴:

<dependency>
	<groupId>commons-logging</groupId>
	<artifactId>commons-logging</artifactId>
	<version>1.1.1</version>
</dependency>
           

jcl它不直接記錄日志,他是通過第三方記錄日志比如log4j,jul等

如果使用jcl來記錄日志,在沒有log4j的依賴情況下,是用jul

如果有了log4依賴則優先使用使用log4j

使用:

// JCL的日志對象是Log
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JCL {
    public static void main(String[] args) {
        // JCL的日志對象是log,通過LogFactory得到的,括号裡面設定的是日志對象的唯一辨別,既可以使用目前類的class也可以自定義名字
        Log log = LogFactory.getLog("JCL");
        log.info("jcl");
    }
}
           

沒有log4j依賴就會使用JUL:

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

有log4j依賴就會使用log4j:

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

JCL=Jakarta commons-logging ,是apache公司開發的一個抽象日志通用架構,本身不實作日志記錄,但是提供了記錄日志的抽象方法即接口(info,debug,error.......),底層通過一個數組存放具體的日志架構的類名,然後循環數組依次去比對這些類名是否在app中被依賴了,如果找到被依賴的則直接使用,是以他有先後順序。

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

上圖為JCL中存放日志技術類名的數組,預設有四個,後面兩個可以忽略,因為已經很老的技術了,現在不怎麼用了。總之使用JCL的話,它對日志技術的優先使用順序是log4j>jul

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

上圖81行就是通過一個類名去load一個class,如果load成功則直接new出來并且傳回使用(隻有項目引用了相應的依賴,類加載器才會把對應的Class加載入JVM,才可以使用forName将日志對象執行個體反射建立)。

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

如果沒有load到class這循環第二個(因為那四個類名是順序存放在那個數組當中的),直到找到為止。

可以看到這裡的循環條件必須滿足result不為空,

也就是如果沒有找到具體的日志依賴則繼續循環,如果找到則條件不成立,不進行循環了。

使用JCL的優點:比如我們有一個項目,A子產品用的是log4j,B子產品用的是jul,如果直接使用這兩個包記錄日志,那麼項目合并之後日記會出現不統一,非常混亂,不容易維護等問題。但是如果A子產品使用JUL來調用log4j,B子產品使用JUL來調用jul,那麼兩個子產品合并之後就能很友善的統一管理,因為都是利用JUL中的Log作為中間件來進行日志管理的。是以使用一個中間件來管理項目日志的話,從長遠角度看,對項目的擴充性是有好處的。

spring4和spring5都内置了JCL

現在JCL已經不更新了,逐漸被淘汰了。現在slf4j取代了JCL,它據有更好的可拓展性

1.4 SLF4J

slf4j他也不記錄日志,通過綁定器綁定一個具體的日志包來完成日志記錄

它引入了兩個新的概念:綁定器(binder)和橋接器(bridge)

它不再像JCL那樣固定隻能支援4中日志包,它可以通過綁定器更加靈活的拓展,每一種日志包有對應一個SLF4J綁定器,需要用什麼日志包來實作記錄日志的功能,就是用對應的綁定器就可以了。是以更加容易拓展,如果出現了新的日志類,隻需要編寫對應的綁定器就可以關聯到SLF4J進行使用了。

使用:

maven依賴:

<!--slf4j依賴-->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>1.7.25</version>
</dependency>
           

1.4.1 綁定器

綁定器依賴

<!--slf4j的JUL綁定器與slf4j依賴的版本号必須相同-->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-jdk14</artifactId>
	<version>1.7.25</version>
</dependency>

<!--slf4j的log4j綁定器與slf4j依賴的版本号必須相同使用log4j綁定器不需要再單獨依賴log4j的包,已經包含到依賴包中了-->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-log4j12</artifactId>
	<version>1.7.25</version>
</dependency>

<!--slf4j的JCL綁定器與slf4j依賴的版本号必須相同不需要單獨依賴JCL包,這個綁定器也包含了JCL-->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-jcl</artifactId>
	<version>1.7.25</version>
</dependency>
           
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SLF4J {
    public static void main(String[] args) {
        // JCL的日志對象是logger,也是通過LoggerFactory獲得的,既可以使用目前類的class作為日志對象辨別也可以使用自定義命名
        Logger logger = LoggerFactory.getLogger(SLF4J.class);
        logger.info("slf4j");
    }
}
           
【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

1.4.2 橋接器

橋接器指的是可以将一種日志類的實作轉接到SLF4J上來,可以友善實作系統的日志統一管理.

比如使用了log4j的橋接器,那麼A子產品使用的是log4j,B子產品使用的是slf4j,使用JUL綁定器,那麼A子產品的log4j日志系統就會轉接到slf4j中,然後在從slf4j中使用JUL綁定器來完成日志記錄,也就将log4j轉換成了JUL。

橋接器依賴:

<!--slf4j的JCL橋接器-->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>jcl-over-slf4j</artifactId>
	<version>1.7.25</version>
</dependency>

<!--slf4j的log4j橋接器-->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>log4j-over-slf4j</artifactId>
	<version>1.7.25</version>
</dependency>
           

添加了橋接器之後,就可以使橋接器對應的日志記錄實作轉接到SLF4J上

缺點:

在項目變複雜的時候就有可能出現循環引用的問題,進而導緻棧溢出。

比如:我将SLF4J使用一個綁定到JCL的綁定器,再使用一個JCL的橋接器将JCL再轉接到SLF4J上,這樣就會出現循環引用的問題

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

1.5 log4j2

1.6 logback

1.7 simple-log

1.8 各種日志技術的關系和作用

【Spring】通用日志架構和spring 5的日志技術新特性一、主流的log技術名詞二、spring日志技術分析

二、spring日志技術分析

2.1 spring4日志技術實作

spring4當中依賴的是原生的JCL,具體工作原理上面已經講了

2.1 spring5日志技術實作

spring5使用的spring的JCL(spring改了jcl的代碼)來記錄日志的,但是jcl不能直接記錄日志,也是采用一個優先的原則來選擇日志包。

spring5将JCL改掉了,不再是原生的那樣使用for循環,而是用一個switch選擇。

源碼:

在抽象類LogFactory中生成log對象

public static Log getLog(String name) {
    switch(logApi) {
    case LOG4J:
        return LogFactory.Log4jDelegate.createLog(name);
    case SLF4J_LAL:
        return LogFactory.Slf4jDelegate.createLocationAwareLog(name);
    case SLF4J:
        return LogFactory.Slf4jDelegate.createLog(name);
    default:
        return LogFactory.JavaUtilDelegate.createLog(name);
    }
}
           

 由上面的源碼可知,它是通過判斷logApi的值來選擇使用的日志包的。而logApi的值是在這個類的靜态方法中生成的

static {
    logApi = LogFactory.LogApi.JUL;
    ClassLoader cl = LogFactory.class.getClassLoader();
    try {
		// 這裡需要注意,這裡是log4j2
        cl.loadClass("org.apache.logging.log4j.spi.ExtendedLogger");
        logApi = LogFactory.LogApi.LOG4J;
    } catch (ClassNotFoundException var6) {
        try {
            cl.loadClass("org.slf4j.spi.LocationAwareLogger");
            logApi = LogFactory.LogApi.SLF4J_LAL;
        } catch (ClassNotFoundException var5) {
            try {
                cl.loadClass("org.slf4j.Logger");
                logApi = LogFactory.LogApi.SLF4J;
            } catch (ClassNotFoundException var4) {
            }
        }
    }
}
           

 它獲目前類加載器,然後按照一定的優先順序依次根據類全限定名加載,如果項目引入了相應的依賴,将class加載入了JVM,那麼就可以成功給logApi指派。但是這裡有一點需要注意,spring5中的JCL中引用的是log4j2,不是log4j,是以直接通過引用log4j的依賴包在spring5項目中是不起作用的,如果想要在spring5中使用log4j就得通過引用SLF4J,然後再通過引用log4j的綁定包來使用log4j,這是sping5與sping4在日志系統上最大的不同。