spring4.0,spring5.0日誌框架詳解(包含部分源碼解析)。

現階段的日誌框架有哪些?

  • log4j    直接記錄日誌
  • jcl      jcl他不直接記錄日誌,他是通過第三方記錄日誌(jul),如果使用jcl來記錄日誌,在沒有log4j的依賴情況下,是用jul如果有了log4j則使用log4j 。jcl=Jakarta commons-logging ,是apache公司開發的一個抽象日誌通用框架,本身不實現日誌記錄,但是提供了記錄日誌的抽象方法即接口(info,debug,error.......),底層通過一個數組存放具體的日誌框架的類名,然後循環數組依次去匹配這些類名是否在app中被依賴了,如果找到被依賴的則直接使用,所以他有先後順序,以下就是jcl中存放日誌技術名的數組,默認有四個,後面兩個可以 忽略。老版本的jdk才能用到第三四種日誌實現。 jcl核心源碼如下圖所示,由圖可知,該循環有個亮點,result==null 才循環執行適配日誌框架,並按照事先定好數組順序依次執行圖二的代碼通過反射創建日誌實現返回,有興趣的朋友可以看看

 

 

  • jul      java自帶的一個日誌記錄的技術,直接使用
  • log4j2
  • slf4j    slf4j他也不記錄日誌,通過綁定器綁定一個具體的日誌記錄來完成日誌記錄(目前的主流日誌框架門面)
  • logback
  • simple-log

畫圖分析下以上日誌的簡單工作機制

代碼風

spring日誌技術分析

spring4與spring5如下  注意5版本與4版本就只有pom文件不一樣其他全部一樣。

5版本pom文件 

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

4版本pom文件

    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.0.9.RELEASE</version>
    </dependency>
    <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
    </dependency>

 

log4j.properties

 log4j.rootLogger=Info, Console  
 #Console
 log4j.appender.Console=org.apache.log4j.ConsoleAppender
 log4j.appender.Console.Target=system.out
 log4j.appender.Console.layout=org.apache.log4j.PatternLayout
 log4j.appender.Console.layout.ConversionPattern=%d (%t) [%p - %l] %m%n
 

 Test測試類

package com.forewei.test;

import com.forewei.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


/**
 * @Author forewei
 * @date 2019-4-17 15:08
 */
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext
                = new AnnotationConfigApplicationContext(AppConfig.class);
        annotationConfigApplicationContext.start();
    }
}

 spring5輸出 由圖可知該輸出肯定不是log4j 

spring4輸出 可以看出已經用log4j打印日誌了

spring4源碼分析  有兩種分析法。

1.通過斷點如下源碼截圖可以判斷出 spring4用的是log4j框架日誌輸出,點開log依賴可以看出該log是jcl框架,所以spring4底層用的是jcl實現。由於jcl實現的核心代碼在上面已分析,這裏就不做重複分析。

 2. 通過maven依賴確定

打開該項目maven依賴可以看出,spring4底層用的是jcl

spring5分析 

1.首先pom文件依賴圖  由圖可知也是用的jcl,但是這個jcl,應該和spring4一樣會用log4j實現,但是仔細看下圖的jcl依賴是spring的jcl依賴 由此可猜想spring5是把原生的jcl改了 所以導致這一結果。

2.源碼分析 源碼位置 org.apache.commons.logging.LogFactory   

這裏我直接把重要代碼部分貼出來並加上自己的註釋

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

package org.apache.commons.logging;

import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.apache.logging.log4j.spi.LoggerContext;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.spi.LocationAwareLogger;

public abstract class LogFactory {
    private static LogFactory.LogApi logApi;

    public LogFactory() {
    }

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

    // 該方法判斷使用哪種日誌實現
    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默認的日誌爲JUL實現
  // 通過這段代碼可以看出 spring5對jcl進行了改寫,jcl源碼上面已經分析不是這種流程
  // 由以下代碼看出spring5改寫的jcl支持log4j2,slf4j
  // 所以spring5在有log4j依賴時用的是默認的jul日誌框架
    static {
        logApi = LogFactory.LogApi.JUL;
        ClassLoader cl = LogFactory.class.getClassLoader();

        try {
            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) {
                    ;
                }
            }
        }

    }

   
}

 終上所訴得出結論:

  • spring4日誌技術實現      spring4當中依賴的是原生的jcl

 

  •  srping5日誌技術實現     spring5使用的spring的jcl(spring改了jcl的代碼)來記錄日誌的,但是jcl不能直接記錄日誌,採用循                                           環優先的原則

有問題的歡迎大家提問,博主有時間會解答。後續博主會出一些spring的源碼技術分享文章!感謝大家的支持!

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章