logback源码阅读-集成slf4j初始化过程(一)

为什么要看logback源码

项目里面log.info log.error 在请求量大的时候某个请求出问题,很难定位到相关日志,所以针对前端统一返回一个id后端日志自动拼接上这个id

 

 

 

 

 

 

 

slf4j的理解

我的理解slf4j是一个抽象的日志接口,并没有具体实现。我们可以通过slf4j集成各种日志框架logback,log4j,common-logging等框架都实现了这些接口

什么是logback

Logback是由log4j创始人设计的另一个开源日志组件,官方网站: http://logback.qos.ch 是log4j的改良版本

具有更快的实现:Logback的内核重写了,在一些关键执行路径上性能提升10倍以上。而且logback不仅性能提升了,初始化内存加载也更小了。

初始化过程

首先我们看一段使用例子

<1> 
protected Logger logger = LoggerFactory.getLogger(this.getClass()); @Test void testInfo() {
logger.info(
"testffffffffffffff"); }

从入口往下看

LoggerFactory

<1>getLogger

org.slf4j.LoggerFactory#getLogge最终传入class name调以下方法

 public static Logger getLogger(String name) {
        //<2>每种日志框架都实现了LoggerFactory 这里就是根据集成的日志框架获得对应的factory
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

<2>getILoggerFactory

org.slf4j.LoggerFactory#getLogger

->

org.slf4j.LoggerFactory#getILoggerFactory

public static ILoggerFactory getILoggerFactory() {
/**
     * 0:未初始化
     * 1:准备初始化
     * 2:类没有实现LoggerFactoryBinder 相关方法
     * 3:获取binder成功
     * 4:没有找到相关类 
     */
    static volatile int INITIALIZATION_STATE = 0;
    //这个工厂创建NOPLogger实例 是个空实现 
    static final NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory();
    public static ILoggerFactory getILoggerFactory() {
        /**
         * 判断是否初始化
         */
        if (INITIALIZATION_STATE == 0) {
            Class var0 = LoggerFactory.class;
            //加锁并判断 防止初始化后释放锁  等待的进来重复加载
            synchronized(LoggerFactory.class) {
                if (INITIALIZATION_STATE == 0) {
                    //标识正在初始化
                    INITIALIZATION_STATE = 1;
                    //<4>执行初始化化绑定
                    performInitialization();
                }
            }
        }

        switch(INITIALIZATION_STATE) {
            case 1:
                return SUBST_FACTORY;
            case 2:
                throw new IllegalStateException("org.slf4j.LoggerFactory in failed state. Original exception was thrown EARLIER. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
            case 3:
                //<5>可以看到此处是根据StaticLoggerBinder 这是一个slf4j继承点 为logback实现 下面会讲 
                return StaticLoggerBinder.getSingleton().getLoggerFactory();
            case 4:
                return NOP_FALLBACK_FACTORY;//如果没有找到相关绑定类 则默认返回空的Factory
            default:
                throw new IllegalStateException("Unreachable code");
        }
    }
}

<3>findPossibleStaticLoggerBinderPathSet

org.slf4j.LoggerFactory#findPossibleStaticLoggerBinderPathSet

 private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
    static Set<URL> findPossibleStaticLoggerBinderPathSet() {
        LinkedHashSet staticLoggerBinderPathSet = new LinkedHashSet();

        try {
            ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
            Enumeration paths;
            if (loggerFactoryClassLoader == null) {
                //搜索位置查找给定资源名称的所有系统资源,以加载类
                paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
            } else {
                //搜索位置查找给定资源名称的所有系统资源,以加载类
                paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
            }

            while(paths.hasMoreElements()) {
                URL path = (URL)paths.nextElement();
                staticLoggerBinderPathSet.add(path);
            }
        } catch (IOException var4) {
            Util.report("Error getting resources from path", var4);
        }

        return staticLoggerBinderPathSet;
    }

 

<4> performInitialization

org.slf4j.LoggerFactory#performInitialization

    private static final void performInitialization() {
        //<6>执行绑定
        bind();
        //3表示成功获取binder实现
        if (INITIALIZATION_STATE == 3) {
            //这里会获取binder的REQUESTED_API_VERSION 里面的静态变量的版本 跟self4j 做比较
            versionSanityCheck();
        }
    }

<6> bind

org.slf4j.LoggerFactory#bind

   private static final void bind() {
        String msg;
        try {
            Set<URL> staticLoggerBinderPathSet = null;
            //判断系统变量:-Djava.vendor.url 是否包含android 默认是不会包含的
            if (!isAndroid()) {
                /**
                 *<3>在classpath查找 org/slf4j/impl/StaticLoggerBinder.class 
                 */
                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
                /**
                 * 检查是否找到多个binder
                 */
                reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            }

            /**
             *1.先触发类加载<8>
*2.获取调用getSingleton 并执行静态初始化逻辑 binder必须有这个方法<7>
*/ StaticLoggerBinder.getSingleton(); //表示获取binder成功 INITIALIZATION_STATE = 3; //重复校验 如果找到多个会报错 reportActualBinding(staticLoggerBinderPathSet); fixSubstituteLoggers(); replayEvents(); SUBST_FACTORY.clear(); } catch (NoClassDefFoundError var2) { msg = var2.getMessage(); if (!messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) { failedBinding(var2); throw var2; } INITIALIZATION_STATE = 4; Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\"."); Util.report("Defaulting to no-operation (NOP) logger implementation"); Util.report("See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details."); } catch (NoSuchMethodError var3) { msg = var3.getMessage(); if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) { INITIALIZATION_STATE = 2; Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding."); Util.report("Your binding is version 1.5.5 or earlier."); Util.report("Upgrade your binding to version 1.6.x."); } throw var3; } catch (Exception var4) { failedBinding(var4); throw new IllegalStateException("Unexpected initialization failure", var4); } }
代码<1>处就是自定义binder返回自定义Logger工厂的扩展点.可以发现binder必须拥有getSingleton 以及上面的版本控制performInitialization获取的 StaticLoggerBinder.REQUESTED_API_VERSION 静态版本变量

StaticLoggerBinder

<5>init

org.slf4j.impl.StaticLoggerBinder#init

void init() {
        try {
            try {
                //<2>委托ContextInitializer初始化LoggerContext 具体后面讲 直通车:点击跳转
                (new ContextInitializer(this.defaultLoggerContext)).autoConfig();
            } catch (JoranException var2) {
                Util.report("Failed to auto configure default logger context", var2);
            }

            /**
             * 如果没有配置文件则使用默认配置文件
             */
            if (!StatusUtil.contextHasStatusListener(this.defaultLoggerContext)) {
                StatusPrinter.printInCaseOfErrorsOrWarnings(this.defaultLoggerContext);
            }
            /**
             * 首先看系统变量是否有配置-Dlogback.ContextSelector="JNDI'配置了返回ContextJNDISelector
             * 如果不等于JNDI则当做自定义ContextSelector 会通过类加载 必须拥有一个参数的构造函数LoggerContext
             * 默认会使用DefaultContextSelector
             */
            this.contextSelectorBinder.init(this.defaultLoggerContext, KEY);
            //标识为初始化成功
            this.initialized = true;
        } catch (Exception var3) {
            Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", var3);
        }

    }

 这里初始化成功上面则会调用

org.slf4j.LoggerFactory#getLogger#getILoggerFactory

->

org.slf4j.impl.StaticLoggerBinder#getLoggerFactory

  public ILoggerFactory getLoggerFactory() {
        //是否初始化成功
        if (!this.initialized) {
            //如果没有返回默认的LoggerContext
            return this.defaultLoggerContext;
        } else if (this.contextSelectorBinder.getContextSelector() == null) {
            throw new IllegalStateException("contextSelector cannot be null. See also http://logback.qos.ch/codes.html#null_CS");
        } else {
            //最终根据contextSelectorBinder 获取LoggerContext
            return this.contextSelectorBinder.getContextSelector().getLoggerContext();
        }
    }

<7>getSingleton

logback对于slf4j接入的实现

org.slf4j.impl.StaticLoggerBinder

private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder();

    public static StaticLoggerBinder getSingleton() {
        return SINGLETON;
    }

<8>

//<5>静态域初始化StaticLoggerBinder
    static {
        SINGLETON.init();
    }

 

 

总结

1.slf4j根据查找是否有StaticLoggerBinder来为集成点必须要有getSingleton()返回当前实例 以及getLoggerFactory()返回工厂对象以及静态变量REQUESTED_API_VERSION logback也有对应的实现

2.log StaticLoggerBinder基于static{}做一些初始化动作 getFactory方法委托ContextSelectorBinder返回工厂对象 可以扩展

4.StaticLoggerBinder的init方法 初始化配置文件是委托给ContextInitializer.init做的

posted @ 2020-01-06 15:52  意犹未尽  阅读(1050)  评论(0编辑  收藏  举报