Logback源码分析 (3)

首先从指定的路径获取资源URL,如果存在就进行解析;如果不存在再从运行环境中获取配置;如果以上都没有最后会构建一个BasicConfigurator当作默认的。

ch.qos.logback.classic.util.ContextInitializer#findURLOfDefaultConfigurationFile

public URL findURLOfDefaultConfigurationFile(boolean updateStatus) { ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this); // 启动参数中获取 URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus); if (url != null) { return url; } // logback-test.xml url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus); if (url != null) { return url; } //logback.groovy url = getResource(GROOVY_AUTOCONFIG_FILE, myClassLoader, updateStatus); if (url != null) { return url; } // logback.xml return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus); }

先从启动参数中查找logback.configurationFile参数值,如果没有再从classpath中一次查找logback-test.xml -> logback.groovy -> logback.xml 。由此可知文件的优先级是 启动参数 -> logback-test.xml -> logback.groovy -> logback.xml

第10步:ch.qos.logback.classic.util.ContextInitializer#configureByResource

public void configureByResource(URL url) throws JoranException { if (url == null) { throw new IllegalArgumentException("URL argument cannot be null"); } final String urlString = url.toString(); if (urlString.endsWith("groovy")) { // 省略代码。。。 } else if (urlString.endsWith("xml")) { JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(loggerContext); configurator.doConfigure(url); } else { // 省略代码。。。 } }

根据文件后缀判断是 groovy或者xml,然后交给不同的配置解析器处理。这里也是把第7步中的LoggerContext传进去,继续封装它的字段值。

第12步:ch.qos.logback.core.joran.GenericConfigurator#doConfigure(org.xml.sax.InputSource)

public final void doConfigure(final InputSource inputSource) throws JoranException { long threshold = System.currentTimeMillis(); SaxEventRecorder recorder = new SaxEventRecorder(context); recorder.recordEvents(inputSource); // 处理配置文件,封装到 LoggerContext 中 playEventsAndProcessModel(recorder.saxEventList); StatusUtil statusUtil = new StatusUtil(context); if (statusUtil.noXMLParsingErrorsOccurred(threshold)) { registerSafeConfiguration(recorder.saxEventList); } }

真正解析配置文件的逻辑在playEventsAndProcessModel方法中,这里就不展开分析了。到这一步LoggerContext基本初始化完成了。

第13步:ch.qos.logback.classic.LoggerContext#getLogger(java.lang.String)

@Override public Logger getLogger(final String name) { // 省略代码。。。 if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) { return root; } int i = 0; Logger logger = root; // 从缓存中获取, 有直接返回 Logger childLogger = (Logger) loggerCache.get(name); 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) 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; } } }

经过前面漫长的对LoggerContext进行初始化工作,这一步就是从LoggerContext获取Logger对象。如果缓存中直接返回。否则通过“.”分代构建层次结构。

日志执行步骤

上一节Logger创建完成,接下来分析一下打日志的流程。

logger.info(" {} is best player in world", "Greizmann");

Logback源码分析

第1步:ch.qos.logback.classic.Logger#info(java.lang.String, java.lang.Object)

public void info(String format, Object arg) { filterAndLog_1(FQCN, null, Level.INFO, format, arg, null); }

把接口的日志级别(Level.INFO)传到下一个方法。

第2步:ch.qos.logback.classic.Logger#filterAndLog_1

private void filterAndLog_1(final String localFQCN, final Marker marker, final Level level, final String msg, final Object param, final Throwable t) { // 先通过turboFilter过滤 final FilterReply decision = loggerContext.getTurboFilterChainDecision_1(marker, this, level, msg, param, t); // 判断日志级别 if (decision == FilterReply.NEUTRAL) { if (effectiveLevelInt > level.levelInt) { return; } } else if (decision == FilterReply.DENY) { return; } buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] { param }, t); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyyxxx.html