源码阅读-logback的LoggerContext的设计以及如何创建Logger


上一篇博客介绍了StaticLoggerBinder如何提供ILoggerFactory的实现类,首先拥有一个默认的LoggerContext的实例,再去初始化该实例(可配置化,可通过配置文件或者java类或者使用默认配置),ContextInitializer是如何初始化LoggerContext的我们后续的博客再讲述。我们先来看看LoggerContext是如何创建核心类Logger实例的。

 从图中可以看到,LoggerContext类除了ILoggerFactory接口之外,还实现了LifeCycle接口,并继承自ContextBase类。同时拥有LoggerContextListener和根Logger两个比较重要的成员变量。

  我们先大致介绍一下LoggerContext的字段和方法。

/**
 *
 * LoggerContext继承ContextBase并实现ILoggerFactory和LifeCycle
 * LoggerContext将许多logback经典组件粘在一起。
 * 原则上,每个logback经典组件实例都直接或间接地附加到LoggerContext实例。
 * 同样重要的是,LoggerContext实现了{@link ILoggerFactory}作为{@link Logger}实例的制造源。
 * @author Ceki Gulcu
 */
public class LoggerContext extends ContextBase implements ILoggerFactory, LifeCycle {

    /** Default setting of packaging data in stack traces */
    public static final boolean DEFAULT_PACKAGING_DATA = false;

    /** 根Logger */
    final Logger root;
    /** size用来表示LoggerContext一共创建了几个Logger*/
    private int size;

    /**
     * 没有Appender警告计数器 原则上只警告一次
     */
    private int noAppenderWarning = 0;
    /**
     * 观察者模式  被观察者(主题):LoggerContext 观察者:多个LoggerContextListener
     * LoggerContext监听器
     */
    final private List<LoggerContextListener> loggerContextListenerList = new ArrayList<LoggerContextListener>();

    /** loggerCache 缓存 所有LoggerContext创建的logger都放在这里*/
    private Map<String, Logger> loggerCache;
    /**loggerContextRemoteView是一个LoggerContext的VO对象,保存了LoggerContext的一些值 */
    private LoggerContextVO loggerContextRemoteView;
    /**
     * 快速过滤器链
     * 通过封装一个TurboFilterList对象(继承一个集合对象),可以将 获取过滤器链结果 方法封装到该对面里面 方法复用
     *
     * 我认为TurboFilterList实例不应放在LoggerContext作为一个成员变量
     * 目前看来 TurboFilterList用来Logger对象的过滤 且LoggerContext没有用到TurboFilterList
     * 反而后续 Logger对象需要维持一个LoggerContext的成员变量的引用(为了用TurboFilterList组件)
     * 我认为应该在Logger类中拥有一个静态的TurboFilterList实例对象
     */
    private final TurboFilterList turboFilterList = new TurboFilterList();
    private boolean packagingDataEnabled = DEFAULT_PACKAGING_DATA;

    private int maxCallerDataDepth = ClassicConstants.DEFAULT_MAX_CALLEDER_DATA_DEPTH;
    /** resetCount是用来统计该LoggerContext调用过几次reset()方法*/
    int resetCount = 0;
    private List<String> frameworkPackages;

 

 构造方法:这个方法基本上是只会调用一次的,在StaticLoggerBinder里

  public LoggerContext() {
        super();
        this.loggerCache = new ConcurrentHashMap<String, Logger>();

        this.loggerContextRemoteView = new LoggerContextVO(this);
        this.root = new Logger(Logger.ROOT_LOGGER_NAME, null, this);
        this.root.setLevel(Level.DEBUG);
        loggerCache.put(Logger.ROOT_LOGGER_NAME, root);
        initEvaluatorMap();
        size = 1;
        this.frameworkPackages = new ArrayList<String>();
    }

 

 方法:

private void incSize() {
        size++;
    }

    int size() {
        return size;
    }
/**
     */
    public Logger exists(String name) {
        return (Logger) loggerCache.get(name);

final void noAppenderDefinedWarning(final Logger logger) {
        if (noAppenderWarning++ == 0) {
            getStatusManager().add(new WarnStatus("No appenders present in context [" + getName() + "] for logger [" + logger.getName() + "].", logger));
        }
    }

/**
     * 获取所有创建的Loggers
     * @return
     */
    public List<Logger> getLoggerList() {
        Collection<Logger> collection = loggerCache.values();
        List<Logger> loggerList = new ArrayList<Logger>(collection);
        Collections.sort(loggerList, new LoggerComparator());
        return loggerList;
    }


/**
     * 重置LoggerContxet
     */
    @Override
    public void reset() {
        resetCount++;
        super.reset();
        initEvaluatorMap();
        initCollisionMaps();
        root.recursiveReset();
        resetTurboFilterList();
        cancelScheduledTasks();
        fireOnReset();
        resetListenersExceptResetResistant();
        resetStatusListeners();
    }


 /**
     * 一层薄封装 我觉得没必要
     * @param newFilter
     */
    public void addTurboFilter(TurboFilter newFilter) {
        turboFilterList.add(newFilter);
    }

    /**
     * First processPriorToRemoval all registered turbo filters and then clear the registration
     * list.
     * 重置快速过滤器链表
     * 我认为这个方法应该 封装在TurboFilterList类中
     */
    public void resetTurboFilterList() {
        for (TurboFilter tf : turboFilterList) {
            tf.stop();
        }
        turboFilterList.clear();
    }

    /**
     * getTurboFilterChainDecision_0_3OrMore
     * getTurboFilterChainDecision_1
     * getTurboFilterChainDecision_2
     * 这一系列奇怪的方法是对TurboFilterList中getTurboFilterChainDecision()的薄封装
     * 至于目的 据作者自己说是为了提高性能
     * @param marker
     * @param logger
     * @param level
     * @param format
     * @param params
     * @param t
     * @return
     */
    final FilterReply getTurboFilterChainDecision_0_3OrMore(final Marker marker, final Logger logger, final Level level, final String format,
                    final Object[] params, final Throwable t) {
        if (turboFilterList.size() == 0) {
            return FilterReply.NEUTRAL;
        }
        return turboFilterList.getTurboFilterChainDecision(marker, logger, level, format, params, t);
    }

    final FilterReply getTurboFilterChainDecision_1(final Marker marker, final Logger logger, final Level level, final String format, final Object param,
                    final Throwable t) {
        if (turboFilterList.size() == 0) {
            return FilterReply.NEUTRAL;
        }
        return turboFilterList.getTurboFilterChainDecision(marker, logger, level, format, new Object[] { param }, t);
    }

    final FilterReply getTurboFilterChainDecision_2(final Marker marker, final Logger logger, final Level level, final String format, final Object param1,
                    final Object param2, final Throwable t) {
        if (turboFilterList.size() == 0) {
            return FilterReply.NEUTRAL;
        }
        return turboFilterList.getTurboFilterChainDecision(marker, logger, level, format, new Object[] { param1, param2 }, t);
    }

    // === start listeners ==============================================

    /**
     * 观察者模式
     * 添加一个监听者
     * @param listener
     */
    public void addListener(LoggerContextListener listener) {
        loggerContextListenerList.add(listener);
    }

    /**
     * 移除一个监听者
     * @param listener
     */
    public void removeListener(LoggerContextListener listener) {
        loggerContextListenerList.remove(listener);
    }


 /**
     * 清空所有的监听者
     */
    private void resetAllListeners() {
        loggerContextListenerList.clear();
    }


void fireOnLevelChange(Logger logger, Level level) {
        for (LoggerContextListener listener : loggerContextListenerList) {
            listener.onLevelChange(logger, level);
        }
    }

    /**
     * 当上下文重置时 通知上下文监听者们
     * 采用“拉”的方式 将自己的引用传递过去
     */
    private void fireOnReset() {
        for (LoggerContextListener listener : loggerContextListenerList) {
            listener.onReset(this);
        }
    }

    /**
     * 当启动上下文时 通知上下文监听者们
     */
    private void fireOnStart() {
        for (LoggerContextListener listener : loggerContextListenerList) {
            listener.onStart(this);
        }
    }

    /**
     * 当停止上下文时 通知上下文监听者们
     */
    private void fireOnStop() {
        for (LoggerContextListener listener : loggerContextListenerList) {
            listener.onStop(this);
        }
    }

    // === end listeners ==============================================

    /**
     * 启动LoggerContxet
     */
    public void start() {
        super.start();
        fireOnStart();
    }

    /**
     * 停止LoggerContxet
     */
    public void stop() {
        reset();
        fireOnStop();
        resetAllListeners();
        super.stop();
    }

 

 接下来我们重点介绍一个核心方法getLogger(String name),LoggerContext如何创建Logger

1.如果name是null,抛出异常。

2.如果请求的是ROOT Logger,那么就直接返回root

3.然后检查一下请求的Logger是否已经创建过了,如果已经创建过,就直接从loggerCache中返回

4.如果还没创建过,那就开始逐层创建,比如请求的Logger的name是com.company.package.ClassName,那么一共会创建4个Logger,分别是Logger[com]、Logger[com.company]、Logger[com.company.package]、Logger[com.company.package.ClassName]

public final Logger getLogger(final Class<?> clazz) {
        return getLogger(clazz.getName());
    }

    @Override
    public final Logger getLogger(final String name) {

        if (name == null) {
            throw new IllegalArgumentException("name argument cannot be null");
        }

        // if we are asking for the root logger, then let us return it without
        // wasting time
        //若是获取根logger直接返回
        if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
            return root;
        }

        int i = 0;
        Logger logger = root;

        // check if the desired logger exists, if it does, return it
        // without further ado.
        //查看loggerCache容器里面是否存在期望的logger,有则直接返回
        Logger childLogger = (Logger) loggerCache.get(name);
        // if we have the child, then let us return it without wasting time
        if (childLogger != null) {
            return childLogger;
        }

        // if the desired logger does not exist, them create all the loggers
        // in between as well (if they don't already exist)
        //如果期望的logger不存在,则创建中间所有的loggers
        String childName;
        while (true) {
            int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
            if (h == -1) {
                childName = name;
            } else {
                childName = name.substring(0, h);
            }
            // move i left of the last point
            i = h + 1;
            synchronized (logger) {
                childLogger = logger.getChildByName(childName);
                if (childLogger == null) {
                    childLogger = logger.createChildByName(childName);
                    loggerCache.put(childName, childLogger);
                    incSize();
                }
            }
            logger = childLogger;
            if (h == -1) {
                return childLogger;
            }
        }
    }

 

上面代码比较清晰,就是根据"."来解析name,然后创建Logger,每创建一个Logger,都放到loggerCache中,并且把size++。

创建Child Logger是有点讲究的,除了创建Logger实例之外,还有维护父子关系,并且处理Level继承的问题,这个是在Logger类的createChildByName(String childName)方法里实现的。我们来先来看看这些方法:

   /**
     * The default size of child list arrays. The JDK 1.5 default is 10. We use a
     * smaller value to save a little space.
     * 根据名称创建子logger
     */

    Logger createChildByName(final String childName) {
        // 检查childName的合法性 是不是该logger的child
        int i_index = LoggerNameUtil.getSeparatorIndexOf(childName, this.name.length() + 1);
        if (i_index != -1) {
            throw new IllegalArgumentException("For logger [" + this.name + "] child name [" + childName
                            + " passed as parameter, may not include '.' after index" + (this.name.length() + 1));
        }

        if (childrenList == null) {
            childrenList = new CopyOnWriteArrayList<Logger>();
        }
        Logger childLogger;
        childLogger = new Logger(childName, this, this.loggerContext);
        childrenList.add(childLogger);
        childLogger.effectiveLevelInt = this.effectiveLevelInt;
        return childLogger;
    }

 

 

    /**
     * 根据名称查询子logger
     * @param childName
     * @return
     */
    Logger getChildByName(final String childName) {
        if (childrenList == null) {
            return null;
        } else {
            int len = this.childrenList.size();
            for (int i = 0; i < len; i++) {
                final Logger childLogger_i = (Logger) childrenList.get(i);
                final String childName_i = childLogger_i.getName();

                if (childName.equals(childName_i)) {
                    return childLogger_i;
                }
            }
            // no child found
            return null;
        }
    }

 

 

/**
     * 为该logger设置等级level
     * @param newLevel
     */
    public synchronized void setLevel(Level newLevel) {
        //赋值level和当前level相等,因为level是固定的几个常量所以用==比较即可,则什么也不做并结束
        if (level == newLevel) {
            // nothing to do;
            return;
        }
        //当该looger为root时,该level不能为null
        if (newLevel == null && isRootLogger()) {
            throw new IllegalArgumentException("The level of the root logger cannot be set to null");
        }

        //赋新值
        level = newLevel;
        if (newLevel == null) {//若newLevel为null,则继承父logger的effectiveLevelInt
            effectiveLevelInt = parent.effectiveLevelInt;
            newLevel = parent.getEffectiveLevel();
        } else {//否则,effectiveLevelInt = newLevel.levelInt
            effectiveLevelInt = newLevel.levelInt;
        }

        if (childrenList != null) {//若子loggers不为空,则为每一个子logger处理他们的effectiveLevelInt的值
            int len = childrenList.size();
            for (int i = 0; i < len; i++) {
                Logger child = (Logger) childrenList.get(i);
                // tell child to handle parent levelInt change
                child.handleParentLevelChange(effectiveLevelInt);
            }
        }
        // inform listeners
        //通知
        loggerContext.fireOnLevelChange(this, newLevel);
    }

    /**
     * This method is invoked by parent logger to let this logger know that the
     * prent's levelInt changed.
     *
     * 递归处理父logger的level变化,该loggere的effectiveLevelInt值处理
     * @param newParentLevelInt
     */
    private synchronized void handleParentLevelChange(int newParentLevelInt) {
        // changes in the parent levelInt affect children only if their levelInt is
        // null
        //当该logger的level为空时,父logger的level变化才会影响子logger的effectiveLevelInt
        //因为当该logger的level不为空时,effectiveLevelInt=level.levelInt,否则effectiveLevelInt继承父logger的effectiveLevelInt
        if (level == null) {
            effectiveLevelInt = newParentLevelInt;

            // propagate the parent levelInt change to this logger's children
            if (childrenList != null) {
                int len = childrenList.size();
                for (int i = 0; i < len; i++) {
                    Logger child = (Logger) childrenList.get(i);
                    child.handleParentLevelChange(newParentLevelInt);
                }
            }
        }

        /**
         * 我写该递归函数的方式
         *  先写该递归函数的终止条件
         *  if (level != null){
         *             return;
         *         }
         *  level为null时处理
         *          effectiveLevelInt = newParentLevelInt;
         *         if (childrenList != null) {
         *             int len = childrenList.size();
         *             for (int i = 0; i < len; i++) {
         *                 Logger child = (Logger) childrenList.get(i);
         *                 child.handleParentLevelChange(newParentLevelInt);
         *             }
         *         }
         */

    }

 

构造方法:this.parent = parent里,设置了父Logger

   Logger(String name, Logger parent, LoggerContext loggerContext) {
        this.name = name;
        this.parent = parent;
        this.loggerContext = loggerContext;
    }

 

 
总结一下创建Logger的完整流程:
1、如果请求ROOT logger,则直接返回root
2、如果请求的Logger已经存在,则直接返回
3、如果请求的Logger尚未创建,则从ROOT开始,级联创建所有Logger
4、每创建一个Logger,都要设置父子关系,继承生效级别
5、每创建一个Logger,都将其放入loggerCache,并将size++

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM