分析spring4和spring5日志中的不同


  日志在工作中起到關鍵作用,我們經常使用它來打印關鍵信息,方便分析,或者是輸出錯誤信息,用於bug排查,spring中同樣使用了日志進行信息的輸出,但是spring4和spring5之間的日志又有些不同,接下來我們就進行一些分析。

1. 各種日志技術簡述:  

    log4j,jul,jcl,log4j2,slf4j

    我們先把他們展示出來,以免引用錯誤。

  1.1 log4j

   使用log4j需要引入log4j的配置文件log4j.properties,內容簡配一下:

log4j.rootLogger = info,stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

  pom文件中只引入log4j所需要的jar包

  

  程序也寫的簡單一點,輸出日志就行:

  

   結果:

  

  日志是輸出的。

 1.2JUL

  JUL 是jdk自帶的,所以pom文件中不需要引入任何包,直接擼代碼:

  

   結果:

  

   日志輸出格式我們不再做改變,記住log4j和jul的日志輸出格式,后面有用到。

 1.3:JCL

  pom中引入所需要的包:

       

 

 

   擼代碼:

  

  結果:

  

   嗚呼,這個日志輸出是不是很眼熟呀,長得很像上面JUL打印出來的日志,難道他們之間有什么不可描述的事情?所以最帥的我准備打開JCL的源碼一探究竟。

  從上面代碼中的LogFactory的getLog方法下手,進去:

  

  木得意思,就一行代碼,那就再深一點,進入getInstance()中,

  

   第一行代碼看着像是拿到了log,不過老哥我已經幫大家踩過坑了,debug走了一遍,第一行代碼執行后,Log 依然是null,所以我們繼續往下走,進入到

this.newInstance()方法中,有點長,就醬紫:

protected Log newInstance(String name) throws LogConfigurationException {
        Log instance = null;

        try {
            Object[] params;
            if (this.logConstructor == null) {
                instance = this.discoverLogImplementation(name);
            } else {
                params = new Object[]{name};
                instance = (Log)this.logConstructor.newInstance(params);
            }

            if (this.logMethod != null) {
                params = new Object[]{this};
                this.logMethod.invoke(instance, params);
            }

            return instance;
        } catch (LogConfigurationException var5) {
            throw var5;
        } catch (InvocationTargetException var6) {
            Throwable c = var6.getTargetException();
            if (c != null) {
                throw new LogConfigurationException(c);
            } else {
                throw new LogConfigurationException(var6);
            }
        } catch (Throwable var7) {
            throw new LogConfigurationException(var7);
        }
    }

  這段代碼差一點就比我的長處還長呢,所以我又幫大家debug了一遍,在第一個if判斷 之后執行的這個方法 this.discoverLogImplementation(name);就是我們要找的,再深入,在

discoverLogImplementation()這個方法中,我找到了這段代碼:

  

  result屬性就是我們需要返回的Log,循環條件中有一個classesToDiscover,並且還把他的值傳給了this.createLogFromClass()方法,點擊看看他是什么,

String[] classesToDiscover = new String[]{"org.apache.commons.logging.impl.Log4JLogger", 
                          "org.apache.commons.logging.impl.Jdk14Logger",
                          "org.apache.commons.logging.impl.Jdk13LumberjackLogger",
                          "org.apache.commons.logging.impl.SimpleLog"};

  這個數組里面找到了 org.apache.commons.logging.impl.Jdk14Logger,這不就是我們的JUL 嗎?再想到剛剛的for循環,我們很容易理解,JCL就是循環這個數組,一次獲取Log,知道Log 不為null為止,為了驗證我們的猜想,

我們可以引入log4j的jar包和配置文件,其他代碼不做修改,這樣按照數組順序,應該打印出來log4j的日志。

      

 

果然,在有log4j的情況下,JCL按照剛剛那個數組,順序加載log,知道Log不為null。

  由此可以看出,JCL起到的是一個中間商賺差價的作用,在有log4j的時候使用log4j,否則使用JUL

2 Sring4 的日志體系

  上面說了那么多,只是介紹了一部分日志技術,接下來我們開始分別分析spring4和spring5的日志體系。

  2.1 構建spring4項目

  采用java+注解的方式快速構建,pom中只引入spring-context包

  

  運行下面的代碼,可以看到有日志輸出

  

 

   

 

   找到打印日志的地方,debug模式下,查看輸出日志的Log是什么log

  

 

  可以看出是jdk14Logger,這個在JCL中說過,這個指的是JUL,也就是說在默認spring日志體系下,采用的是JUL,

  接下來,我們按照之前的方法引入log4j,debug運行上面的程序,再次查看日志類型

  

 

  額,這次在增加log4j jar包和配置文件的情況下,spring4有使用了log4j,這么像JCL呢,木錯,讓我們在idea中打開spring4的日志依賴結構:

  

  common-logging 這不就是JCL使用到的包嗎,可以看出,Spring4使用的是原生的JCL,所以在有log4j的時候使用log4j打印日志,沒有的時候使用JUL打印日志。

3.Spring5日志體系

  線上依賴結構圖:

  

 

   答題結構沒變,只是原來common-logging ,換成了spring-jcl,看名字就知道是spring自造的包,jcl,更是標注了,它使用的是JCL日志體系。

  所以還是看源碼吧。

  按照之前的經驗,我們只用debug找到spring內部一個Log,看看他的產生方式和類型。這次我給大家找了AbstractApplicationContext里面找到產生Log的地方

  

 

  進入這個方法的getLog()中,一直深入,不要憐惜spring,找到LogAdapter中的createLog()方法

  

 

   可以看出來spring5中對日志的生產,不在像原生JCL中那樣使用一個數組,然后進行循環產生,這里用到的是Switch case,這個關鍵字段LogApi又是在哪一部分賦值的呢?看圖

  

 

   Duang ,沒錯是在靜態代碼塊中賦的值,為了驗證,我們准備用其中提到的log4j2驗證(注意:log4j不行,因為這里的switch沒有log4j選項),首先我們准備log4j2的配置文件

  

<Configuration status="WARN">

<Appenders>

<Console name="Console" target="SYSTEM_OUT">

<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>

</Console>

</Appenders>

<Loggers>

<Root level="debug">

<AppenderRef ref="Console"/>

</Root>

</Loggers>

</Configuration>

  然后准備pom

  

   代碼還是這一行,直接運行:

           

  結果有日志打印出來了

  

 

   所以,在spring5中,依然使用的是JCL,但是不是原生的,是經過改造的JCL,默認使用的是JUL,而原生JCL中默認使用的是log4j.

 

  好了,就醬紫,求輕拍,大家中秋快樂。

 

 

  

  

 

 

 

  

 

  

 

 

      

      

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM