private static final Log logger = LogFactory.getLog(SpringProperties.class);java
對於使用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()!例如,考慮這個公共代碼位,它在某個基類中聲明:字符串
//記錄器聲明不太好get
protected final Log log = LogFactory.getLog(getClass());博客
爲何這麼糟糕?嗯,它不是靜態的。另外一方面,它使用getClass()來獲取日誌。起初,這彷佛頗有效,由於如今全部子類都自動繼承了正確運行時類型的現成的日誌。這裏出了什麼問題?以這種方式聲明的日誌記錄器的最大問題是,您如今從超類中得到的全部日誌記錄與子類的日誌記錄混合在一塊兒,而且在日誌輸出中,除非您查看源代碼,不然沒法識別哪些消息來自哪一個類。若是超類有不少您不想看到的日誌記錄,這是很是煩人的,由於您不能過濾掉它。class
另外一個問題是,您以不一樣的方式設置日誌級別的能力消失了,例如,若是子類駐留在與超類不一樣的包中。在這種狀況下,若是試圖從超類中篩選出日誌記錄,則不能,由於實際的運行時類用於獲取日誌記錄器。擴展
最後,擁有一個受保護的記錄器彷佛違反了基本的面向對象原則。爲何子類應該從橫切關注點的超類瞭解內部實現細節?不管如何,雖然這是一個愚蠢的小咆哮,可是當您擴展一個聲明像這樣的受保護日誌記錄器的超類時,它確實很煩人。