SLF4J(五) - Marker使用的误区- 源码分析

x33g5p2x  于2021-12-28 转载在 其他  
字(2.5k)|赞(0)|评价(0)|浏览(575)

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

}

相关文章