SLF4J(五) - Marker使用的誤區- 源碼分析

在之前的文章中我也分享過,如果去使用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);
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章