zoukankan      html  css  js  c++  java
  • 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

    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做的

  • 相关阅读:
    HDU.5765.Bonds(DP 高维前缀和)
    SPOJ.TLE
    LOJ.2585.[APIO2018]新家(二分 线段树 堆)
    BZOJ.2679.Balanced Cow Subsets(meet in the middle)
    BZOJ.3293.[CQOI2011]分金币(思路)
    BZOJ.4558.[JLOI2016]方(计数 容斥)
    BZOJ.3631.[JLOI2014]松鼠的新家(树上差分)
    BZOJ.1568.[JSOI2008]Blue Mary开公司(李超线段树)
    BZOJ.1071.[SCOI2007]组队(思路)
    BZOJ.4910.[SDOI2017]苹果树(树形依赖背包 DP 单调队列)
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12156738.html
Copyright © 2011-2022 走看看