zoukankan      html  css  js  c++  java
  • SLF4J源码解析-LoggerFactory(二)

    承接前文SLF4J源码解析-LoggerFactory(一),本文则主要针对获取ILoggerFactory对象作下简单的分析

    LoggerFactory#getILoggerFactory()

    源码如下

      public static ILoggerFactory getILoggerFactory() {
       ***
       ***
        
        switch (INITIALIZATION_STATE) {
        case SUCCESSFUL_INITILIZATION:
          return StaticLoggerBinder.getSingleton().getLoggerFactory();
        case NOP_FALLBACK_INITILIZATION:
          return NOP_FALLBACK_FACTORY;
        case FAILED_INITILIZATION:
          throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
        case ONGOING_INITILIZATION:
          // support re-entrant behavior.
          // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
          return TEMP_FACTORY;
        }
        throw new IllegalStateException("Unreachable code");
      }
    

    根据前文的分析,SL4J获取Logger对象需要classpath下拥有StaticLoggerBinder类,本文则选取logback API来作解析

    StaticLoggerBinder.getSingleton().getLoggerFactory()-成功初始化状态下的获取ILoggerFactory()

    StaticLoggerBinder.getSingleton()-获取StaticLoggerBinder实例

    此处我们只需要分析下StaticLoggerBinder的静态初始化块

      static {
        SINGLETON.init();
      }
    

    紧接着看下init()方法

      void init() {
        try {
          try {
            //此处的defaultLoggerContext为LoggerContext
            //此处也会去加载配置文件
            new ContextInitializer(defaultLoggerContext).autoConfig();
          } catch (JoranException je) {
            Util.report("Failed to auto configure default logger context", je);
          }
          // logback-292
          //检查是否defaultLoggerContext注册了StatusListener
          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);
        }
      }
    

    看下ContextInitializer如何加载相应的配置文件

    ContextInitializer#autoConfig()

    直接看源码

      public void autoConfig() throws JoranException {
    	//判断系统变量logback.statusListenerClass是否设定,设定了则注册
    	//StatusListener
        StatusListenerConfigHelper.installIfAsked(loggerContext);
        //查找相应的配置文件,我们可以简单的看下
        URL url = findURLOfDefaultConfigurationFile(true);
        if (url != null) {
          //加载相应的配置文件
          configureByResource(url);
        } else {
    	  //没有则创建名为console的ConsoleAppender
          BasicConfigurator.configure(loggerContext);
        }
      }
    

    我们看下ContextInitializer如何查找配置文件

    ContextInitializer#findURLOfDefaultConfigurationFile()

    直接阅读源码

      public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
        ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
        //首先查找系统变量logback.configurationFile指定的配置文件
        URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
        if (url != null) {
          return url;
        }
        //反之则查找classpath下是否存在名为logback.groovy配置文件
        url = getResource(GROOVY_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
          return url;
        }
        //反之则查找classpath下是否存在名为logback-test.xml配置文件
        url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
          return url;
        }
    	//最后则查找classpath下是否存在名为logback.xml的配置文件
        return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus);
      }
    

    根据源码整理下logback加载配置文件的顺序

    1. 查找系统变量logback.configurationFile指定的配置文件

    2. 上述不存在则查找classpath下是否存在名为logback.groovy配置文件

    3. 上述不存在则查找classpath下是否存在名为logback-test.xml配置文件

    4. 最后查找classpath下是否存在名为logback.xml的配置文件

    注意:此处的classpath特指根目录下,web环境下一般指WEB-INF/classes根目录

    ContextInitializer#configureByResource()-加载指定的配置文件

    具体源码如下

      public void configureByResource(URL url) throws JoranException {
        //指定的文件查找不到则抛出异常
        if (url == null) {
          throw new IllegalArgumentException("URL argument cannot be null");
        }
        //针对结尾为groovy的配置文件进行解析
        if (url.toString().endsWith("groovy")) {
          if (EnvUtil.isGroovyAvailable()) {
            // avoid directly referring to GafferConfigurator so as to avoid
            // loading  groovy.lang.GroovyObject . See also http://jira.qos.ch/browse/LBCLASSIC-214
            GafferUtil.runGafferConfiguratorOn(loggerContext, this, url);
          } else {
            StatusManager sm = loggerContext.getStatusManager();
            sm.add(new ErrorStatus("Groovy classes are not available on the class path. ABORTING INITIALIZATION.",
                    loggerContext));
          }
        }
        //对结尾为xml的文件进行解析
        if (url.toString().endsWith("xml")) {
          JoranConfigurator configurator = new JoranConfigurator();
          configurator.setContext(loggerContext);
          configurator.doConfigure(url);
        }
      }
    

    具体的解析步骤就不讲解了,读者有兴趣可自行去分析

    NOPLoggerFactory#NOP_FALLBACK_INITILIZATION状态下生成的ILoggerFactory

    此日志工厂主要生成不打印任何日志的Logger对象

    小结

    通过分析源码我们可以得知其他的API是如何结合SL4J来实现Logger原理的。本文是以logback为例的,具体的逻辑可见本文的详细内容

  • 相关阅读:
    python 计时累积超过24小时时继续往上累加
    linux 下获取文件最后几行
    unbuntu 安装python包提示E: Unable to locate package python-timeout
    python 计时器
    jquery中html()、text()、val()的区别
    DESC和 ACS
    jQuery自动截取文字长度,超过部分
    Spring MVC 注解
    注解笔记
    Spring Data JPA初使用 *****重要********
  • 原文地址:https://www.cnblogs.com/question-sky/p/7429548.html
Copyright © 2011-2022 走看看