ava 界里有許多實現日志功能的工具,最早得到廣泛使用的是 log4j,許多應用程序的日志部分都交給了 log4j,不過作為組件開發者,他們希望自己的組件不要緊緊依賴某一個工具,畢竟在同一個時候還有很多其他很多日志工具,假如一個應用程序用到了兩個組件,恰好兩個組件使用不同的日志工具,那么應用程序就會有兩份日志輸出了。
為了解決這個問題,Apache Commons Logging (之前叫 Jakarta Commons Logging,JCL)粉墨登場,JCL 只提供 log 接口,具體的實現則在運行時動態尋找。這樣一來組件開發者只需要針對 JCL 接口開發,而調用組件的應用程序則可以在運行時搭配自己喜好的日志實踐工具。
所以即使到現在你仍會看到很多程序應用 JCL + log4j 這種搭配,不過當程序規模越來越龐大時,JCL的動態綁定並不是總能成功,具體原因大家可以 Google 一下,這里就不再贅述了。解決方法之一就是在程序部署時靜態綁定指定的日志工具,這就是 SLF4J 產生的原因。
跟 JCL 一樣,SLF4J 也是只提供 log 接口,具體的實現是在打包應用程序時所放入的綁定器(名字為 slf4j-XXX-version.jar)來決定,XXX 可以是 log4j12, jdk14, jcl, nop 等,他們實現了跟具體日志工具(比如 log4j)的綁定及代理工作。舉個例子:如果一個程序希望用 log4j 日志工具,那么程序只需針對 slf4j-api 接口編程,然后在打包時再放入 slf4j-log4j12-version.jar 和 log4j.jar 就可以了。
現在還有一個問題,假如你正在開發應用程序所調用的組件當中已經使用了 JCL 的,還有一些組建可能直接調用了 java.util.logging,這時你需要一個橋接器(名字為 XXX-over-slf4j.jar)把他們的日志輸出重定向到 SLF4J,所謂的橋接器就是一個假的日志實現工具,比如當你把 jcl-over-slf4j.jar 放到 CLASS_PATH 時,即使某個組件原本是通過 JCL 輸出日志的,現在卻會被 jcl-over-slf4j “騙到”SLF4J 里,然后 SLF4J 又會根據綁定器把日志交給具體的日志實現工具。過程如下
Component
|
| log to Apache Commons Logging
V
jcl-over-slf4j.jar --- (redirect) ---> SLF4j ---> slf4j-log4j12-version.jar ---> log4j.jar ---> 輸出日志
看到上面的流程圖可能會發現一個有趣的問題,假如在 CLASS_PATH 里同時放置 log4j-over-slf4j.jar 和 slf4j-log4j12-version.jar 會發生什么情況呢?沒錯,日志會被踢來踢去,最終進入死循環。
所以使用 SLF4J 的比較典型搭配就是把 slf4j-api、JCL 橋接器、java.util.logging(JUL)橋接器、log4j 綁定器、log4j 這5個 jar 放置在 CLASS_PATH 里。
不過並不是所有APP容器都是使用 log4j 的,比如 Google AppEngine 它使用的是 java.util.logging(JUL),這時應用 SLF4J 的搭配就變成 slf4j-api、JCL橋接器、logj4橋接器、JUL綁定器這4個 jar 放置在 WEB-INF/lib 里。