2010-10-01 63 views
81

應該將記錄器聲明爲靜態還是不是?通常我看到兩種類型的聲明爲Logger:應該將記錄器設置爲靜態還是不需要

 
    protected Log log = new Log4JLogger(aClass.class); 

 
    private static Log log = new Log4JLogger(aClass.class); 

哪一個應該被使用?什麼是兩者的贊成和反對?

+1

伐木是一個橫切關注。使用方面,問題是沒有意義的。 – 2010-10-03 05:26:23

+2

'static'是每個類的一個參考。非靜態**是每個實例**一個參考**(+初始化)。所以在某些情況下,如果你有很多實例,後者會對內存產生重大影響。切勿在*頻繁*對象中使用非靜態。我總是使用靜態版本。 (應該是* uppercased *'LOG') – 2012-09-05 08:43:29

+0

如果你使用[jcabi-log](http://www.jcabi.com/jcabi-log/),一個靜態的包裝器,你可以根本不需要這個變量slf4j – yegor256 2012-10-05 07:19:37

回答

83

非靜態形式的好處是,你可以在一個(抽象)基類,而不必擔心正確類名稱將用於類似如下聲明它:

protected Log log = new Log4JLogger(getClass()); 

但是它的缺點是很明顯的是將爲每個類的實例創建一個全新的記錄器實例。這本身可能並不昂貴,但是會增加很大的開銷。如果您想避免這種情況,您想使用static表單代替。但是它的缺點是你必須在每個單獨的類中聲明它,並在每個類中注意在記錄器的構造過程中使用了正確的類名,因爲getClass()不能在靜態上下文中使用。但是,在平均IDE中,您可以爲此創建一個自動完成模板。例如。 logger + ctrl+space。另一方面,如果您通過工廠獲取記錄器,而工廠又可以緩存已經實例化的記錄器,那麼使用非靜態的表單不會增加太多的開銷。爲此,Log4j例如有一個LogManager

protected Log log = LogManager.getLogger(getClass()); 
+5

在抽象類中聲明'abstract Log getLogger();'。實現此方法,爲特定實例返回靜態記錄器。將'private final static Log LOG = LogManager.getLogger(Clazz.class);'添加到您的IDE類模板中。 – 2012-09-05 08:45:45

+2

對於slf4j:'protected Logger log = LoggerFactory.getLogger(getClass());' – 2014-12-18 11:18:20

+0

@BalusC將getClass()傳遞給getLogger方法的問題在於它返回當前實例的類。通常情況下,日誌更需要與代碼所在的類相關聯。例如,如果日誌記錄代碼在Parent類中,那麼即使執行實例是Parent的子類Child的實例,我們也希望日誌記錄與Parent相關聯。使用getClass()它將與子項關聯,錯誤地 – inor 2018-02-26 11:31:38

2

使用控制反轉並將記錄器傳遞給構造函數。如果你在課堂上創建了記錄器,你將在你的單元測試中有一段時間的魔鬼。你正在寫單元測試不是嗎?

+2

單元測試檢查您正在生成的日誌聲音既無用又令人難以置信的脆弱。 – Michael 2017-11-10 11:52:00

+0

有用性取決於被測系統。有時記錄是你有權訪問的。 – 2017-11-15 22:45:30

+0

@Wayne Allen當你在進行單元測試時,根據定義,你也有測試結果。你是否暗示了一種單元測試但沒有測試結果的情況?只有日誌? – inor 2018-02-20 15:54:02

12

最重要的區別是它如何影響你的日誌文件:日誌去哪個類別?

  • 在您的第一個選擇中,子類的日誌以超類的類別結束。這對我來說似乎非常不直觀。
  • 還有就是你的第一種情況的變體:

    保護的登錄日誌=新Log4JLogger(的getClass());

    在這種情況下,您的日誌類別表示記錄的代碼正在處理哪個對象。

  • 在您的第二個選擇(私有靜態)中,日誌類別是包含日誌代碼的類。所以通常是正在做記錄事情的類。

我強烈建議最後一個選項。與其他解決方案相比,它具有以下優點:

  • 日誌和代碼之間有直接關係。很容易找到日誌消息來自哪裏。
  • 如果有人需要調整日誌級別(這是每個類別完成的),通常是因爲他們對特定的消息感興趣(或不是),由特定的類編寫。如果該類別不是正在編寫消息的類,則很難調整這些級別。
  • 您可以登錄靜態方法
  • 記錄儀只需要進行初始化(或擡頭)每班一次,因此在啓動時,而不是爲每個實例創建。

它也有缺點:

  • 它需要在每一個類,你記錄消息(無父記錄器的再利用)進行聲明。
  • 初始化記錄器時,需要注意輸入正確的類名。 (但好的IDE爲你照顧)。
38

我曾經認爲所有的記錄器應該是靜態的;然而,this article at wiki.apache.org帶來了一些關於類加載器泄漏的重要內存問題。將記錄器聲明爲靜態可防止聲明類(和關聯的類加載器)在使用共享類加載器的J2EE容器中被垃圾收集。如果重新部署應用程序足夠多次,這將導致PermGen錯誤。

我真的沒有辦法解決這個類加載器泄漏問題,除了聲明記錄器是非靜態的。

+4

我懷疑靜態字段也會有內存泄漏問題。正如其他人所說,非靜態可能會有性能問題。那麼理想的方式是什麼? – liang 2013-10-08 07:26:39

+0

@piepera在你引用的文章中描述的主要問題是,當「考慮使用」private static Log log =「的類通過多重祖先的ClassLoader部署時,可以控制每個應用程序中的日誌級別據稱是獨立的「應用程序」「。我不認爲這是一個問題,因爲在這種特殊情況下,應用程序有一個「共同點」,並且「共同點」決定了該類的日誌級別,是的,它適用於所有應用程序......但保留記住這個類在這些應用程序之外[加載] – inor 2018-02-20 16:21:45

相關問題