上一篇博客介紹了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++