logback配置文件加载顺序是怎样的?

2026-05-22 06:361阅读0评论SEO资讯
  • 内容介绍
  • 相关推荐

本文共计1273个文字,预计阅读时间需要6分钟。

logback配置文件加载顺序是怎样的?

logback配置文件加载过程很简单,以下是一份简要记录:

1. Maven项目中,logback-classic已包含logback-core和slf4j依赖,无需额外添加。

2.无需手动引入groupId和artifactId,Maven会自动处理。

配置文件示例:

xml

%d{yyyy-MM-dd HH:mm:ss} - %msg%n

logback的配置文件加载过程还是很简单的,这里做一下简单记录

1、maven

logback-classic已经包含了logback-coreslf4j的依赖,不需要额外引入了

<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.10</version> </dependency> 2、入口

平时我们使用 logback入口都是 LoggerFactory.getLogger() 这个 api,我们debug就从这里进入

public static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); }

进入 getILoggerFactory()方法
这个方法里面使用了一堆常量,这里简单介绍

常量 含义 UNINITIALIZED 还未初始化,需要初始化日志环境 SUCCESSFUL_INITIALIZATION 成功初始化,可以执行获取日志对象 NOP_FALLBACK_INITIALIZATION 已经初始化了,但是没有只有门面,没有实现,所以会返回 NOPLoggerFactory ,这个工厂中创建的日志对象什么都不处理,也就是打印不出来日志 FAILED_INITIALIZATION 初始化失败,无法使用,会报错 ONGOING_INITIALIZATION 正在初始化,表明多线程环境下,第一个线程使用已经开始初始化了,但是还没有初始化完成,第二个线程又进来这时候就会返回一个SubstituteLoggerFactory,临时使用这个日志工厂创建日志对象 INITIALIZATION_STATE 当前的slf4j的状态,默认为UNINITIALIZED

public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { synchronized (LoggerFactory.class) { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITIALIZATION; performInitialization(); } } } switch (INITIALIZATION_STATE) { case SUCCESSFUL_INITIALIZATION: return StaticLoggerBinder.getSingleton().getLoggerFactory(); case NOP_FALLBACK_INITIALIZATION: return NOP_FALLBACK_FACTORY; case FAILED_INITIALIZATION: throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); case ONGOING_INITIALIZATION: // support re-entrant behavior. // See also jira.qos.ch/browse/SLF4J-97 return SUBST_FACTORY; } throw new IllegalStateException("Unreachable code"); }

详细的流程这里不说了,因为我们要看的是日志的配置文件加载过程,所以此时第一次进入肯定是未初始化UNINITIALIZED,只需要看performInitialization方法即可,我们进入

logback配置文件加载顺序是怎样的?

private final static void performInitialization() { bind(); if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) { versionSanityCheck(); } }

绑定完成后,会将当前状态修改为初始化完成,我们进入 bind方法

private final static void bind() { try { Set<URL> staticLoggerBinderPathSet = null; if (!isAndroid()) { staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); } // 日志绑定对象 StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; reportActualBinding(staticLoggerBinderPathSet); } catch (NoClassDefFoundError ncde) { //省略异常处理流程 } }

StaticLoggerBinder是个单例,它初始化的过程,不仅决定使用那个实现,还决定配置文件的加载,我们进入getSingleton方法

private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); static { SINGLETON.init(); } public static StaticLoggerBinder getSingleton() { return SINGLETON; }

可以看到StaticLoggerBinder在实例化过程中,会调用init方法,我们进入

void init() { try { try { new ContextInitializer(defaultLoggerContext).autoConfig(); } catch (JoranException je) { Util.report("Failed to auto configure default logger context", je); } // logback-292 if (!StatusUtil.contextHasStatusListener(defaultLoggerContext)) { StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext); } contextSelectorBinder.init(defaultLoggerContext, KEY); initialized = true; } catch (Exception t) { // see LOGBACK-1159 Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", t); } }

这里面紧急执行了 autoConfig方法,我们进入

public void autoConfig() throws JoranException { StatusListenerConfigHelper.installIfAsked(loggerContext); //获取默认的配置文件url,源码可见2.1 URL url = findURLOfDefaultConfigurationFile(true); // 如果获取到则进行配置 if (url != null) { configureByResource(url); } // 没有获取到默认的配置文件url,则继续判断 else { // 通过jdk的spi机制获取配置文件对象,源码可见2.2 Configurator c = EnvUtil.loadFromServiceLoader(Configurator.class); // 获取到配置文件对象,则对loggerContext进行配置 if (c != null) { try { c.setContext(loggerContext); c.configure(loggerContext); } catch (Exception e) { throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass() .getCanonicalName() : "null"), e); } } // 未获取到配置文件对象,则使用BasicConfigurator进行配置, else { BasicConfigurator basicConfigurator = new BasicConfigurator(); basicConfigurator.setContext(loggerContext); basicConfigurator.configure(loggerContext); } } } 2.1、获取默认的配置文件url

public URL findURLOfDefaultConfigurationFile(boolean updateStatus) { // 获取配置文件 ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this); // 获取系统变量中指定的名为,logback.configurationFile,的配置文件 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.xml的配置文件 return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus); } 2.2、通过java spi 获取配置对象

public static <T> T loadFromServiceLoader(Class<T> c) { ServiceLoader<T> loader = ServiceLoader.load(c, getServiceLoaderClassLoader()); Iterator<T> it = loader.iterator(); if (it.hasNext()) return it.next(); return null; } 3、总结

在第一次获取Logger对象时,会加载配置文件,顺序是

  1. 系统变量中的名为 logback.configurationFile的配置文件
  2. 类路径下的名为 logback-test.xml的配置文件
  3. 类路径下的名为 logback-test.xml的配置文件
  4. java spi 机制实现了ch.qos.logback.classic.spi.Configurator接口的类
  5. 默认的配置类BasicConfigurator

本文共计1273个文字,预计阅读时间需要6分钟。

logback配置文件加载顺序是怎样的?

logback配置文件加载过程很简单,以下是一份简要记录:

1. Maven项目中,logback-classic已包含logback-core和slf4j依赖,无需额外添加。

2.无需手动引入groupId和artifactId,Maven会自动处理。

配置文件示例:

xml

%d{yyyy-MM-dd HH:mm:ss} - %msg%n

logback的配置文件加载过程还是很简单的,这里做一下简单记录

1、maven

logback-classic已经包含了logback-coreslf4j的依赖,不需要额外引入了

<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.10</version> </dependency> 2、入口

平时我们使用 logback入口都是 LoggerFactory.getLogger() 这个 api,我们debug就从这里进入

public static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); }

进入 getILoggerFactory()方法
这个方法里面使用了一堆常量,这里简单介绍

常量 含义 UNINITIALIZED 还未初始化,需要初始化日志环境 SUCCESSFUL_INITIALIZATION 成功初始化,可以执行获取日志对象 NOP_FALLBACK_INITIALIZATION 已经初始化了,但是没有只有门面,没有实现,所以会返回 NOPLoggerFactory ,这个工厂中创建的日志对象什么都不处理,也就是打印不出来日志 FAILED_INITIALIZATION 初始化失败,无法使用,会报错 ONGOING_INITIALIZATION 正在初始化,表明多线程环境下,第一个线程使用已经开始初始化了,但是还没有初始化完成,第二个线程又进来这时候就会返回一个SubstituteLoggerFactory,临时使用这个日志工厂创建日志对象 INITIALIZATION_STATE 当前的slf4j的状态,默认为UNINITIALIZED

public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { synchronized (LoggerFactory.class) { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITIALIZATION; performInitialization(); } } } switch (INITIALIZATION_STATE) { case SUCCESSFUL_INITIALIZATION: return StaticLoggerBinder.getSingleton().getLoggerFactory(); case NOP_FALLBACK_INITIALIZATION: return NOP_FALLBACK_FACTORY; case FAILED_INITIALIZATION: throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); case ONGOING_INITIALIZATION: // support re-entrant behavior. // See also jira.qos.ch/browse/SLF4J-97 return SUBST_FACTORY; } throw new IllegalStateException("Unreachable code"); }

详细的流程这里不说了,因为我们要看的是日志的配置文件加载过程,所以此时第一次进入肯定是未初始化UNINITIALIZED,只需要看performInitialization方法即可,我们进入

logback配置文件加载顺序是怎样的?

private final static void performInitialization() { bind(); if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) { versionSanityCheck(); } }

绑定完成后,会将当前状态修改为初始化完成,我们进入 bind方法

private final static void bind() { try { Set<URL> staticLoggerBinderPathSet = null; if (!isAndroid()) { staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); } // 日志绑定对象 StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; reportActualBinding(staticLoggerBinderPathSet); } catch (NoClassDefFoundError ncde) { //省略异常处理流程 } }

StaticLoggerBinder是个单例,它初始化的过程,不仅决定使用那个实现,还决定配置文件的加载,我们进入getSingleton方法

private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); static { SINGLETON.init(); } public static StaticLoggerBinder getSingleton() { return SINGLETON; }

可以看到StaticLoggerBinder在实例化过程中,会调用init方法,我们进入

void init() { try { try { new ContextInitializer(defaultLoggerContext).autoConfig(); } catch (JoranException je) { Util.report("Failed to auto configure default logger context", je); } // logback-292 if (!StatusUtil.contextHasStatusListener(defaultLoggerContext)) { StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext); } contextSelectorBinder.init(defaultLoggerContext, KEY); initialized = true; } catch (Exception t) { // see LOGBACK-1159 Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", t); } }

这里面紧急执行了 autoConfig方法,我们进入

public void autoConfig() throws JoranException { StatusListenerConfigHelper.installIfAsked(loggerContext); //获取默认的配置文件url,源码可见2.1 URL url = findURLOfDefaultConfigurationFile(true); // 如果获取到则进行配置 if (url != null) { configureByResource(url); } // 没有获取到默认的配置文件url,则继续判断 else { // 通过jdk的spi机制获取配置文件对象,源码可见2.2 Configurator c = EnvUtil.loadFromServiceLoader(Configurator.class); // 获取到配置文件对象,则对loggerContext进行配置 if (c != null) { try { c.setContext(loggerContext); c.configure(loggerContext); } catch (Exception e) { throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass() .getCanonicalName() : "null"), e); } } // 未获取到配置文件对象,则使用BasicConfigurator进行配置, else { BasicConfigurator basicConfigurator = new BasicConfigurator(); basicConfigurator.setContext(loggerContext); basicConfigurator.configure(loggerContext); } } } 2.1、获取默认的配置文件url

public URL findURLOfDefaultConfigurationFile(boolean updateStatus) { // 获取配置文件 ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this); // 获取系统变量中指定的名为,logback.configurationFile,的配置文件 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.xml的配置文件 return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus); } 2.2、通过java spi 获取配置对象

public static <T> T loadFromServiceLoader(Class<T> c) { ServiceLoader<T> loader = ServiceLoader.load(c, getServiceLoaderClassLoader()); Iterator<T> it = loader.iterator(); if (it.hasNext()) return it.next(); return null; } 3、总结

在第一次获取Logger对象时,会加载配置文件,顺序是

  1. 系统变量中的名为 logback.configurationFile的配置文件
  2. 类路径下的名为 logback-test.xml的配置文件
  3. 类路径下的名为 logback-test.xml的配置文件
  4. java spi 机制实现了ch.qos.logback.classic.spi.Configurator接口的类
  5. 默认的配置类BasicConfigurator