`

读logback源码系列文章(二)——提供ILoggerFactory

阅读更多
上篇博客介绍了logback是怎么对接slf4j的,简言之,就是通过下面这行代码
return StaticLoggerBinder.getSingleton().getLoggerFactory();

slf4j委托具体实现框架的StaticLoggerBinder来返回一个ILoggerFactory,从而对接到具体实现框架上

这篇博客就接下来介绍一下,logback的StaticLoggerBinder类是怎么创建ILoggerFactory的



在图中可以看到,在logback里,ILoggerFactory的实现类是LoggerContext

logback的StaticLoggerBinder类实现了LoggerFactoryBinder接口,这个接口有两个方法
public interface LoggerFactoryBinder {

  /**
   * Return the instance of {@link ILoggerFactory} that 
   * {@link org.slf4j.LoggerFactory} class should bind to.
   * 
   * @return the instance of {@link ILoggerFactory} that 
   * {@link org.slf4j.LoggerFactory} class should bind to.
   */
  public ILoggerFactory getLoggerFactory();

  /**
   * The String form of the {@link ILoggerFactory} object that this 
   * <code>LoggerFactoryBinder</code> instance is <em>intended</em> to return. 
   * 
   * <p>This method allows the developer to intterogate this binder's intention 
   * which may be different from the {@link ILoggerFactory} instance it is able to 
   * yield in practice. The discrepency should only occur in case of errors.
   * 
   * @return the class name of the intended {@link ILoggerFactory} instance
   */
  public String getLoggerFactoryClassStr();
}

其中比较重要的是getLoggerFactory()方法,其实自定义的StaticLoggerBinder类不实现这个接口也是可以的,只要能保证提供getLoggerFactory()方法,并返回一个ILoggerFactory就可以了

下面就来具体地看看StaticLoggerBinder类的代码:

首先,该类必须有一个getSingleton()方法,来返回该类的单例
private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder();

public static StaticLoggerBinder getSingleton() {
    return SINGLETON;
  }

以上代码用了比较简单的单例模式,提供getSingleton()方法是对接slf4j的强制要求

然后这个类用了一个static块来保证初始化
static {
    SINGLETON.init();
  }

void init() {
    try {
      try {
        new ContextInitializer(defaultLoggerContext).autoConfig();
      } catch (JoranException je) {
        Util.report("Failed to auto configure default logger context", je);
      }
      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);
    }
  }

这个初始化方法init()里做了2件事

第一件事是委托ContextInitializer类对defaultLoggerContext进行初始化。这里如果找到了任一配置文件,就会根据配置文件去初始化LoggerContext,如果没找到,会使用默认配置。关于LoggerContext是怎么根据配置文件进行配置的,在后面的博客中介绍,这里先略过

第二件事是对ContextSelectorStaticBinder类进行初始化
public void init(LoggerContext defaultLoggerContext, Object key) throws ClassNotFoundException,
      NoSuchMethodException, InstantiationException, IllegalAccessException,
      InvocationTargetException  {
    if(this.key == null) {
      this.key = key;
    } else if (this.key != key) {
      throw new IllegalAccessException("Only certain classes can access this method.");
    }
    
    
    String contextSelectorStr = OptionHelper
        .getSystemProperty(ClassicConstants.LOGBACK_CONTEXT_SELECTOR);
    if (contextSelectorStr == null) {
      contextSelector = new DefaultContextSelector(defaultLoggerContext);
    } else if (contextSelectorStr.equals("JNDI")) {
      // if jndi is specified, let's use the appropriate class
      contextSelector = new ContextJNDISelector(defaultLoggerContext);
    } else {
      contextSelector = dynamicalContextSelector(defaultLoggerContext,
          contextSelectorStr);
    }
  }

如果系统参数中配置了JNDI,这里会得到一个ContextJNDISelector,实际应用中,一般会得到一个DefaultContextSelector,并且把已经初始化完成的defaultLoggerContext传给新创建的这个DefaultContextSelector

经过上面的步骤,StaticLoggerBinder的init()方法就走完了,接下来就会调用到关键的getLoggerFactory()方法
public ILoggerFactory getLoggerFactory() {
    if (!initialized) {
      return defaultLoggerContext;
    }

    if (contextSelectorBinder.getContextSelector() == null) {
      throw new IllegalStateException(
          "contextSelector cannot be null. See also " + NULL_CS_URL);
    }
    return contextSelectorBinder.getContextSelector().getLoggerContext();
  }

可以看到,这里有2条分支,如果initialized是false,那么会直接返回defaultLoggerContext。否则就委托刚才提到的ContextSelectorStaticBinder返回一个ContextSelector(一般就是DefaultContextSelector),然后由ContextSelector来返回LoggerContext
public class DefaultContextSelector implements ContextSelector {

  private LoggerContext context;
  
  public DefaultContextSelector(LoggerContext context) {
    this.context = context;
  }
  
  public LoggerContext getLoggerContext() {
    return getDefaultLoggerContext();
  }

  public LoggerContext getDefaultLoggerContext() {
    return context;
  }
}

可以看到,代码有点绕,不过逻辑还是很清楚的

总结一下这个过程:
1、StaticLoggerBinder在加载的时候,会去读取配置文件,并根据配置文件对LoggerContext进行初始化
2、然后初始化ContextSelectorStaticBinder,在这个类内部new一个DefaultContextSelector,并把第一步中配置完毕的LoggerContext传给DefaultContextSelector
3、调用getLoggerFactory()方法,直接返回第一步中配置的LoggerContext,或者委托DefaultContextSelector类返回LoggerContext
  • 大小: 181.7 KB
分享到:
评论

相关推荐

    springboot、logback源码解读

    springboot、logback源码解读,对logback从初始化到,配置文件加载到日志打印,所有步骤的源码分析

    logback-1.1.2源码包

    包含所有的jar包和源代码 logback-core logback-classic logback-access pom.xml

    扩展logback将日志输出到Kafka实例源码

    扩展logback将日志输出到Kafka实例源码,详情请参见博文:http://blog.csdn.net/l1028386804/article/details/79135948

    logback源代码

    rar包中包括:logback源代码,以及struts2的基础的页面跳转,logback虽然是开源的,但它依赖的jar包找全不也不容易,当然你也可以用Maven去下载是最好的喽。 你可以访问:...

    SpringBoot中自定义日志配置logback-spring.xml示例源码

    SpringBoot中自定义日志配置logback-spring.xml示例源码

    logback+slf4j的JAR包和源码

    只要里面的logback-classic-1.1.7,logback-core-1.1.7,slf4j-api-1.7.21的JAR就可以打印出日志信息,而带有source表示对应的JAR包的源代码。可以要也可以不要

    Slf4j+logback实现logback测试

    Slf4j+logback实现logback测试,Slf4j+logback实现logback测试

    logback-1.0.1

    国内可能打不开官网,所以在这里转载,提供下载。 Logback 1.0.1 发布了,这是一个 bugfix 版本,修复了不少的 bug。 Logback是由log4j创始人设计的又一个开源日志组件。logback当前分成三个模块:logback-core,...

    Android代码-logback

    Spring Security源码分析二:Spring Security 授权过程 Spring Security源码分析三:Spring Social 实现QQ社交登录 Spring Security源码分析四:Spring Social 实现微信社交登录 Spring Security源码分析五:Spring ...

    spring boot logback demo

    spring boot logback demo 源码可见:https://github.com/kent124454731/spring-boot-logback。 logback的一些说明可参见文章:http://blog.csdn.net/u011794238/article/details/50770557 如有乱码问题可参见:...

    扩展logback将日志输出到Kafka实例扩展源码

    扩展logback将日志输出到Kafka实例扩展源码,详情参见博文:http://blog.csdn.net/l1028386804/article/details/79136841

    logback下载 日志文件jar包

    内置三个jar包 一个配置文件 logback.txt logback-classic-1.2.3.jar logback-core-1.2.3.jar slf4j-api-1.7.26.jar

    Logback类库含logback.xml配置文件

    该压缩包包含 logback类库所包含的jar包以及logback.xml配置文件(放到 src 目录),用于开发学习使用。

    logback.的jar包

    此zip包含logback-access-1.2.3和logback-classic-1.2.3和logback-core-1.2.3

    Logback所需的jar包

    免费获取Logback所需的jar包 打包合集 让你少走弯路 一.logback简介 1.logback: Logback是由log4j创始人设计的另一个开源日志...二.logback优于log4的原因 Logback对log4j进行了大量改进,Logback就是更好的log4j

    logback-core-1.2.10-API文档-中文版.zip

    赠送jar包:logback-core-1.2.10.jar; 赠送原API文档:logback-core-1.2.10-javadoc.jar; 赠送源代码:logback-core-1.2.10-sources.jar; 赠送Maven依赖信息文件:logback-core-1.2.10.pom; 包含翻译后的API文档...

    logback.jar包

    日志组件logback jar包,logback-access-1.1.3.jar logback-classic-1.1.3.jar logback-core-1.1.3.jar slf4j-api-1.7.12.jar

    logback-0.9.18.zip

    logback-0.9.18.zip 官网下载

    LogBack 中文开发手册

    Logback 中文手册,清晰版. 简单地说,Logback 是一个 Java 领域的日志框架。它被认为是 Log4J 的继承人。 Logback 主要由三个模块组成: logback-core logback-classic logback-access

    logback jar包和logback.xml配置文件打包下载 小白新手学Java

    slf4j-api-1.7.26.jar logback-core-1.2.3.jar logback-classic-1.2.3.jar logback.xml

Global site tag (gtag.js) - Google Analytics