聊聊LogbackMDCAdapter

本文主要研究一下LogbackMDCAdapter

MDCAdapter

org/slf4j/spi/MDCAdapter.java

public interface MDCAdapter {

    /**
     * Put a context value (the val parameter) as identified with
     * the key parameter into the current thread's context map. 
     * The key parameter cannot be null. The val parameter
     * can be null only if the underlying implementation supports it.
     * 
     * 

If the current thread does not have a context map it is created as a side * effect of this call. */ public void put(String key, String val); /** * Get the context identified by the key parameter. * The key parameter cannot be null. * * @return the string value identified by the key parameter. */ public String get(String key); /** * Remove the context identified by the key parameter. * The key parameter cannot be null. * *

* This method does nothing if there is no previous value * associated with key. */ public void remove(String key); /** * Clear all entries in the MDC. */ public void clear(); /** * Return a copy of the current thread's context map, with keys and * values of type String. Returned value may be null. * * @return A copy of the current thread's context map. May be null. * @since 1.5.1 */ public Map getCopyOfContextMap(); /** * Set the current thread's context map by first clearing any existing * map and then copying the map passed as parameter. The context map * parameter must only contain keys and values of type String. * * Implementations must support null valued map passed as parameter. * * @param contextMap must contain only keys and values of type String * * @since 1.5.1 */ public void setContextMap(Map contextMap); /** * Push a value into the deque(stack) referenced by 'key'. * * @param key identifies the appropriate stack * @param value the value to push into the stack * @since 2.0.0 */ public void pushByKey(String key, String value); /** * Pop the stack referenced by 'key' and return the value possibly null. * * @param key identifies the deque(stack) * @return the value just popped. May be null/ * @since 2.0.0 */ public String popByKey(String key); /** * Returns a copy of the deque(stack) referenced by 'key'. May be null. * * @param key identifies the stack * @return copy of stack referenced by 'key'. May be null. * * @since 2.0.0 */ public Deque getCopyOfDequeByKey(String key); /** * Clear the deque(stack) referenced by 'key'. * * @param key identifies the stack * * @since 2.0.0 */ public void clearDequeByKey(String key); }

slf4j定义了MDCAdapter接口,该接口定义了put、get、remove、clear、getCopyOfContextMap、setContextMap、pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey方法

LogbackMDCAdapter

ch/qos/logback/classic/util/LogbackMDCAdapter.java

public class LogbackMDCAdapter implements MDCAdapter  {


    // BEWARE: Keys or values placed in a ThreadLocal should not be of a type/class
    // not included in the JDK. See also https://jira.qos.ch/browse/LOGBACK-450

    final ThreadLocal> readWriteThreadLocalMap = new ThreadLocal>();
    final ThreadLocal> readOnlyThreadLocalMap = new ThreadLocal>();
    private final ThreadLocalMapOfStacks threadLocalMapOfDeques = new ThreadLocalMapOfStacks();

    //......

}      

LogbackMDCAdapter实现了MDCAdapter接口,它基于readWriteThreadLocalMap、readOnlyThreadLocalMap、threadLocalMapOfDeques来实现

readWriteThreadLocalMap

    public void put(String key, String val) throws IllegalArgumentException {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        Map current = readWriteThreadLocalMap.get();
        if (current == null) {
            current = new HashMap();
            readWriteThreadLocalMap.set(current);
        }

        current.put(key, val);
        nullifyReadOnlyThreadLocalMap();
    }
    
    @Override
    public String get(String key) {
        Map hashMap = readWriteThreadLocalMap.get();

        if ((hashMap != null) && (key != null)) {
            return hashMap.get(key);
        } else {
            return null;
        }
    }

    @Override
    public void remove(String key) {
        if (key == null) {
            return;
        }

        Map current = readWriteThreadLocalMap.get();
        if (current != null) {
            current.remove(key);
            nullifyReadOnlyThreadLocalMap();
        }
    }

    @Override
    public void clear() {
        readWriteThreadLocalMap.set(null);
        nullifyReadOnlyThreadLocalMap();
    }

    private void nullifyReadOnlyThreadLocalMap() {
        readOnlyThreadLocalMap.set(null);
    }  

    public void setContextMap(Map contextMap) {
        if (contextMap != null) {
            readWriteThreadLocalMap.set(new HashMap(contextMap));
        } else {
            readWriteThreadLocalMap.set(null);
        }
        nullifyReadOnlyThreadLocalMap();
    }      

put、get、remove、clear、setContextMap都是基于readWriteThreadLocalMap,同时修改操作会同时调用nullifyReadOnlyThreadLocalMap,将readOnlyThreadLocalMap设置为null

getCopyOfContextMap

    public Map getCopyOfContextMap() {
        Map readOnlyMap = getPropertyMap();
        if (readOnlyMap == null) {
            return null;
        } else {
            return new HashMap(readOnlyMap);
        }
    }

    public Map getPropertyMap() {
        Map readOnlyMap = readOnlyThreadLocalMap.get();
        if (readOnlyMap == null) {
            Map current = readWriteThreadLocalMap.get();
            if (current != null) {
                final Map tempMap = new HashMap(current);
                readOnlyMap = Collections.unmodifiableMap(tempMap);
                readOnlyThreadLocalMap.set(readOnlyMap);
            }
        }
        return readOnlyMap;
    }    

getCopyOfContextMap方法通过getPropertyMap获取,如果不为null则新创建HashMap返回;getPropertyMap先从readOnlyThreadLocalMap读取,如果readOnlyThreadLocalMap为null则从readWriteThreadLocalMap拷贝一份unmodifiableMap,并设置到readOnlyThreadLocalMap

threadLocalMapOfDeques

    @Override
    public void pushByKey(String key, String value) {
        threadLocalMapOfDeques.pushByKey(key, value);
    }

    @Override
    public String popByKey(String key) {
        return threadLocalMapOfDeques.popByKey(key);
    }

    @Override
    public Deque getCopyOfDequeByKey(String key) {
        return threadLocalMapOfDeques.getCopyOfDequeByKey(key);
    }

    @Override
    public void clearDequeByKey(String key) {
        threadLocalMapOfDeques.clearDequeByKey(key);
    }

pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey均是基于threadLocalMapOfDeques,它是ThreadLocalMapOfStacks类型

ThreadLocalMapOfStacks

org/slf4j/helpers/ThreadLocalMapOfStacks.java

public class ThreadLocalMapOfStacks {

    // BEWARE: Keys or values placed in a ThreadLocal should not be of a type/class
    // not included in the JDK. See also https://jira.qos.ch/browse/LOGBACK-450

    final ThreadLocal>> tlMapOfStacks = new ThreadLocal<>();

    public void pushByKey(String key, String value) {
        if (key == null)
            return;

        Map> map = tlMapOfStacks.get();

        if (map == null) {
            map = new HashMap<>();
            tlMapOfStacks.set(map);
        }

        Deque deque = map.get(key);
        if (deque == null) {
            deque = new ArrayDeque<>();
        }
        deque.push(value);
        map.put(key, deque);
    }

    public String popByKey(String key) {
        if (key == null)
            return null;

        Map> map = tlMapOfStacks.get();
        if (map == null)
            return null;
        Deque deque = map.get(key);
        if (deque == null)
            return null;
        return deque.pop();
    }

    public Deque getCopyOfDequeByKey(String key) {
        if (key == null)
            return null;

        Map> map = tlMapOfStacks.get();
        if (map == null)
            return null;
        Deque deque = map.get(key);
        if (deque == null)
            return null;

        return new ArrayDeque(deque);
    }
    
    /**
     * Clear the deque(stack) referenced by 'key'. 
     * 
     * @param key identifies the  stack
     * 
     * @since 2.0.0
     */
    public void clearDequeByKey(String key) {
        if (key == null)
            return;

        Map> map = tlMapOfStacks.get();
        if (map == null)
            return;
        Deque deque = map.get(key);
        if (deque == null)
            return;
        deque.clear();
    }

}

ThreadLocalMapOfStacks是slf4j定义的,基于ThreadLocal>>实现的

小结

slf4j定义了MDCAdapter接口,该接口定义了put、get、remove、clear、getCopyOfContextMap、setContextMap、pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey方法;LogbackMDCAdapter实现了MDCAdapter接口,它基于readWriteThreadLocalMap、readOnlyThreadLocalMap、threadLocalMapOfDeques来实现,其中put、get、remove、clear、setContextMap都是基于readWriteThreadLocalMap,pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey均是基于threadLocalMapOfDeques。

你可能感兴趣的:(java,logback)