天天看點

阿裡巴巴開發手冊強制使用SLF4J作為門面擔當的秘密,被我發現了(3)

第四步,在 resources 目錄下建立 log4j.properties 檔案,内容如下所示:

### 設定###

log4j.rootLogger = debug,stdout,D

### 輸出資訊到控制台 ###

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

### 輸出DEBUG 級别以上的日志到=debug.log ###

log4j.appender.D = org.apache.log4j.DailyRollingFileAppender

log4j.appender.D.File = debug.log

log4j.appender.D.Append = true

log4j.appender.D.Threshold = DEBUG

log4j.appender.D.layout = org.apache.log4j.PatternLayout

log4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

再次運作 Demo 類,你會發現 target 目錄下會生成一個名叫 debug.log 的檔案,内容如下所示:

2020-10-21 15:32:06  [ main:0 ] - [ INFO ]  jcl

1

并且可以在控制台看到以下資訊:

[INFO ] 2020-10-21 15:32:06,192 method:com.itwanger.Demo.main(Demo.java:12)

jcl

2

仔細對比一下,你就會發現,這次輸出的格式和之前不一樣,這就是因為 Log4j 和 JUL 的日志格式不同導緻的。

另外,你有沒有發現?我們并沒有改動測試類 Demo,它裡面使用的仍然是 JCL 擷取 Log 的方式:

private static Log logger = LogFactory.getLog(Demo.class);

但輸出的格式已經切換到 Log4j 了!

SLF4J 除了提供這種解決方案,綁定 Log4j 替換 JUL 和 JCL;還提供了綁定 Logback 替換 JUL、JCL、Log4j 的方案:

阿裡巴巴開發手冊強制使用SLF4J作為門面擔當的秘密,被我發現了(3)
還有綁定 JUL 替換 JCL 和 Log4j 的方案:
阿裡巴巴開發手冊強制使用SLF4J作為門面擔當的秘密,被我發現了(3)

太強了,有木有?有的話請在留言區敲出 666。

03、SLF4J 比 Log4J 強在哪

SLF4J 除了解決掉以上的痛點,幫助我們的應用程式獨立于任何特定的日志系統,還有一個非常牛逼的功能,那就是 SLF4J 在列印日志的時候使用了占位符 {},它有點類似于 String 類的 format() 方法(使用 %s 等填充參數),但更加便捷,這在很大程度上提高了程式的性能。

衆所周知,字元串是不可變的,字元串拼接會建立很多不必要的字元串對象,極大的消耗了記憶體空間。但 Log4J 在列印帶參數的日志時,隻能使用字元串拼接的方式:

String name = "沉默王二";

int age = 18;

logger.debug(name + ",年紀:" + age + ",是個非常不要臉的程式員");

非常笨重,但加入了 SLF4J 後,這個問題迎刃而解。我們來看一下在 Log4j 項目中加入 SLF4J 的詳細的步驟。

第一步,把 log4j 的依賴替換為 slf4j-log4j12(Maven 會自動引入 slf4j-api.jar 和 log4j.jar):

<dependency>

   <groupId>org.slf4j</groupId>

   <artifactId>slf4j-log4j12</artifactId>

   <version>1.7.25</version>

</dependency>

第二步,在 resources 目錄下建立 log4j.properties 檔案,内容和 Log4j 那一篇完全相同:

### 設定###
log4j.rootLogger = debug,stdout,D,E
### 輸出資訊到控制台 ###
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
### 輸出DEBUG 級别以上的日志到=debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
### 輸出ERROR 級别以上的日志到=error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n      

第三步,建立測試類:

package com.itwanger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @author 微信搜「沉默王二」,回複關鍵字 PDF
 */
public class Log4jSLF4JDemo {
    private static final Logger logger = LoggerFactory.getLogger(Log4jSLF4JDemo.class);
    public static void main(String[] args) {
        logger.debug("{},是個非常不要臉的程式員","沉默王二");
    }
}      

看到了吧,使用占位符要比“+”操作符友善的多。并且此時不再需要 isDebugEnabled() 先進行判斷,debug() 方法會在字元串拼接之前執行。

如果隻是 Log4J 的話,會先進行字元串拼接,再執行 debug() 方法,來看示例代碼:

在調試這段代碼的時候,你會發現的,如下圖所示:

阿裡巴巴開發手冊強制使用SLF4J作為門面擔當的秘密,被我發現了(3)

這也就意味着,如果日志系統的級别不是 DEBUG,就會多執行了字元串拼接的操作,白白浪費了性能。

注意,阿裡巴巴開發手冊上還有一條「強制」級别的規約:

阿裡巴巴開發手冊強制使用SLF4J作為門面擔當的秘密,被我發現了(3)

這是因為如果參數是基本資料類型的話,會先進行自動裝箱(Integer.valueOf())。測試代碼如下所示:

logger.debug("沉默王二,{}歲", 18);

通過反編譯工具就可以看得到:

logger.debug("\u6C89\u9ED8\u738B\u4E8C\uFF0C{}\u5C81", Integer.valueOf(18));

如果參數需要調用其他方法的話,debug() 方法會随後調用。

阿裡巴巴開發手冊強制使用SLF4J作為門面擔當的秘密,被我發現了(3)

也就是說,如果不 isDebugEnabled() 的話,在不是 DEBUG 級别的情況下,會多執行自動裝箱和調用其他方法的操作——程式的性能就下降了!

測試類運作的結果和之前 Log4J 的一樣,小夥伴們可以點選連結跳轉到 Log4j 那篇對比下。

04、總結

簡單總結一下這篇文章哈。

1)在使用日志系統的時候,一定要使用 SLF4J 作為門面擔當。

2)SLF4J 可以統一日志系統,作為上層的抽象接口,不需要關注底層的日志實作,可以是 Log4j,也可以是 Logback,或者 JUL、JCL。

3)SLF4J 在列印日志的時候可以使用占位符,既提高了程式性能(臨時字元串少了,垃圾回收的工作量就小),又讓代碼變得美觀統一。

4)小夥伴們如果知道更多秘密的話,建議在留言區貼出來哦。

繼續閱讀