在之前的文章中我也分享過,如果去使用Marker標記不同的日誌來源, 用來簡單的做日誌分類, 但最近發現使用的過程中有誤區,可能會導致以後的替換日誌實現框架的時候出現不兼容的問題。
以Log4j的實現爲例
誤區
使用日誌實現類的Marker來創建Marker,如以下的代碼:
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.slf4j.Log4jMarker;
import org.slf4j.Marker;
private static final Marker MARKER = new Log4jMarker(MarkerManager.getMarker("test_marker"));
這樣使用起來是沒啥問題,但如果把日誌框架Log4j給替換掉的時候,就不能做到無痛替換,項目中所有這樣創建Marker的地方都必須修改,這樣就失去了使用SLF4J的意義。
爲什麼這樣寫也能使用呢?
因爲Log4jMarker繼承了org.slf4j.Marker
正確的使用方式
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
private static final Marker MARKER = MarkerFactory.getMarker("test_marker");
slf4j.MarkerFactory是怎麼綁定到log4j的呢?
看看MarkerFactory的源碼就知道了
import org.slf4j.helpers.BasicMarkerFactory;
import org.slf4j.helpers.Util;
import org.slf4j.spi.SLF4JServiceProvider;
public class MarkerFactory {
static IMarkerFactory MARKER_FACTORY;
private MarkerFactory() {
}
// this is where the binding happens
static {
SLF4JServiceProvider provider = LoggerFactory.getProvider();
if (provider != null) {
//執行provider的初始化
provider.initialize();
//之前分析過,provider是用來綁定實現類的LoggerFactory和MarkerFacotry的,因此可以通過provider來獲取綁定的MarkerFactory
MARKER_FACTORY = provider.getMarkerFactory();
} else {
//這裏是打印日誌
Util.report("Failed to find provider");
Util.report("Defaulting to BasicMarkerFactory.");
//如果沒有MarkerFactory,那就採用默認的實現
MARKER_FACTORY = new BasicMarkerFactory();
}
}
public static Marker getMarker(String name) {
return MARKER_FACTORY.getMarker(name);
}
// 省略部分代碼...
BasicMarkerFactory分析
- 實現並不複雜,就是使用ConcurrentHashMap來存儲Marker信息,方法都是實現了IMarkerFactory接口而已
- 新建了一個BasicMarker類,實現Marker接口,比較簡單就不貼代碼了
感興趣的話,可以看看BasicMarkerFactory代碼:
package org.slf4j.helpers;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.slf4j.IMarkerFactory;
import org.slf4j.Marker;
public class BasicMarkerFactory implements IMarkerFactory {
private final ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<String, Marker>();
public BasicMarkerFactory() {
}
public Marker getMarker(String name) {
if (name == null) {
throw new IllegalArgumentException("Marker name cannot be null");
}
Marker marker = markerMap.get(name);
if (marker == null) {
marker = new BasicMarker(name);
Marker oldMarker = markerMap.putIfAbsent(name, marker);
if (oldMarker != null) {
marker = oldMarker;
}
}
return marker;
}
/**
* Does the name marked already exist?
*/
public boolean exists(String name) {
if (name == null) {
return false;
}
return markerMap.containsKey(name);
}
public boolean detachMarker(String name) {
if (name == null) {
return false;
}
return (markerMap.remove(name) != null);
}
public Marker getDetachedMarker(String name) {
return new BasicMarker(name);
}
}