為什麼日誌要private static final
private static final Log logger = LogFactory.getLog(SpringProperties.class);
對於使用PMD的任何人來說,如果日誌記錄器沒有宣告為靜態的和final的,那麼這個部落格的標題就會出現在PMD錯誤列表中。具體地說,LoggerIsNotStaticFinal規則簡單地說日誌應該宣告為靜態的和final的。我也喜歡確保他們是私人的。例如:
//雅加達公共日誌記錄
private static final Log log = LogFactory.getLog(MyClass.class);
上面的程式碼還顯示了另一個好的實踐,即將Class物件傳遞給getLog()方法,而不是字串。為什麼java.util...Logger類甚至不提供接受Class物件的方法呢?為什麼開發java.util.logging包的人將他們的API建立在Log4j上,卻忽略了其中一些最有用的部分?哦,好吧。
現在說正題。為什麼宣告日誌記錄器是私有的、靜態的和final的良好實踐呢?日誌記錄器是一個內部實現細節,因此它應該是私有的。對於類的所有例項,您只需要一個日誌記錄器,因此是靜態的。並且記錄器不能被替換,因此是最終的。所以如果這是好的,有什麼不好的(至少在我看來)?Simple——任何不是私有的、靜態的、final的記錄器,並且不會將Class物件傳遞給getLog()!例如,考慮這個公共程式碼位,它在某個基類中宣告:
//記錄器宣告不太好
protected final Log log = LogFactory.getLog(getClass());
為什麼這麼糟糕?嗯,它不是靜態的。另一方面,它使用getClass()來獲取日誌。起初,這似乎很有效,因為現在所有子類都自動繼承了正確執行時型別的現成的日誌。這裡出了什麼問題?以這種方式宣告的日誌記錄器的最大問題是,您現在從超類中獲得的所有日誌記錄與子類的日誌記錄混合在一起,並且在日誌輸出中,除非您檢視原始碼,否則無法識別哪些訊息來自哪個類。如果超類有很多您不想看到的日誌記錄,這是非常煩人的,因為您不能過濾掉它。
另一個問題是,您以不同的方式設定日誌級別的能力消失了,例如,如果子類駐留在與超類不同的包中。在這種情況下,如果試圖從超類中篩選出日誌記錄,則不能,因為實際的執行時類用於獲取日誌記錄器。
最後,擁有一個受保護的記錄器似乎違反了基本的面向物件原則。為什麼子類應該從橫切關注點的超類瞭解內部實現細節?無論如何,雖然這是一個愚蠢的小咆哮,但是當您擴充套件一個宣告像這樣的受保護日誌記錄器的超類時,它確實很煩人。