slf4j加载过程(基于logback实现)

2021-08-21  本文已影响0人  bclz

主流的Web框架spring boot默认使用slf4j + logback,slf4j 为日志处理提供了统一的接口,比较代表的实现org.apache.log4j、ch.qos.logback等。
主要内容 logback的一般加载过程:

1. slf4j + logback maven集成

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.7</version>
</dependency>

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.1.7</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.1.7</version>
</dependency>

2. 基本使用

package com.bclz;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Program: logback-test
 * @Description: logback测试
 * @Author: c
 * @Date: 2021-08-17 18:36
 */
public class Test {

    private static final Logger LOGGER= LoggerFactory.getLogger(Test.class);

    public static void main(String[] args) {

        LOGGER.info("测试普通日志...");
        LOGGER.error("测试错误日志...");
    }

}


3. 源码分析

关键方法分析

  1. getILoggerFactory()

    public static ILoggerFactory getILoggerFactory() {
    if (INITIALIZATION_STATE == UNINITIALIZED) {
      INITIALIZATION_STATE = ONGOING_INITIALIZATION;
      performInitialization();
    }
    switch (INITIALIZATION_STATE) {
      case SUCCESSFUL_INITIALIZATION:
        //如果初始化成功,则调用StaticLoggerBinder单例的getLoggerFactory()方法获得LoggerFactory工厂对象
        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 http://bugzilla.slf4j.org/show_bug.cgi?id=106
        return TEMP_FACTORY;
    }
    throw new IllegalStateException("Unreachable code");
    }
    
  2. performInitialization()初始化

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

至此,完成"org/slf4j/impl/StaticLoggerBinder.class"路径的查找,该实现类在logback-classic包中,slf4j的具体实现就是通过这种方式查找绑定的。

  1. StaticLoggerBinder.getSingleton()

该方法返回SINGLETON。
具体在类加载的静态代码块中初始化:

        static {
            SINGLETON.init();
        }
            /**
             * Package access for testing purposes.
             */
            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 (Throwable t) {
                    // we should never get here
                    Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", t);
                }
            }

关键方法上下文初始化器的 <font color='red'>new ContextInitializer(defaultLoggerContext).autoConfig();</font>

            public void autoConfig() throws JoranException {
                StatusListenerConfigHelper.installIfAsked(loggerContext);
                //查找默认配置文件  
                URL url = findURLOfDefaultConfigurationFile(true);
                if (url != null) {
                    configureByResource(url);
                } else {
                    Configurator c = EnvUtil.loadFromServiceLoader(Configurator.class);
                    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);
                        }
                    } else {
                        //没有配置文件,则使用打印控制台的默认配置
                        BasicConfigurator basicConfigurator = new BasicConfigurator();
                        basicConfigurator.setContext(loggerContext);
                        basicConfigurator.configure(loggerContext);
                    }
                }
            }

再看看findURLOfDefaultConfigurationFile方法,就是查找具体路径的实现了

       public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
               // 获取当前实例的类加载器
               ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
               //logback.configurationFile
               URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
               if (url != null) {
                   return url;
               }
               
               //再找logback.groovy
               url = getResource(GROOVY_AUTOCONFIG_FILE, 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);
           }

至此xml配置文件加载完毕

上一篇 下一篇

猜你喜欢

热点阅读