美文网首页
Slf4j 源码解析二-添加 slf4j-simple 日志实现

Slf4j 源码解析二-添加 slf4j-simple 日志实现

作者: 当当一丢丢 | 来源:发表于2018-02-14 12:01 被阅读91次
    主题
    • 本篇是Slf4j 源码解析的第二篇,上篇介绍了无日志实现框架的执行流程
    • 本篇解析添加 slf4j-simple 日志实现框架的脉络
    • 已经知道:org/sfl4j/impl/StaticLoggerBinder.class 是连接日志实现框架和Slf4j facade 的桥梁
    先浏览下slf4j-simple.jar的目录结构
    • 关键是探求如何与Slf4j-api.jar facade 关联的,实现框架项目的复杂简单 not care
    //如下是 slf4j-simple.jar 项目的结构示意图
    //最主要的就是 org.slf4j.impl 包路径
    
    slf4j-simple 
        src
            main
                java //sources
                    org.slf4j.impl //package
                        SimpleLogger.java
                        SimpleLoggerFactory.java
                        StaticLoggerBinder.java
                        SimpleLoggerConfiguration.java
                        ......
                resources
                    
        ......
        ......
        pom.xml
    

    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
        <modelVersion>4.0.0</modelVersion>
        
        <parent>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-parent</artifactId>
        <version>1.7.25</version>
        </parent>
        
        <artifactId>slf4j-simple</artifactId>
        <packaging>jar</packaging>
        <name>SLF4J Simple Binding</name>
        <description>SLF4J Simple binding</description>
        <url>http://www.slf4j.org</url>
        
        
        <dependencies>
            <!--添加了slf4j-api依赖,因为要继承其各种接口,如 Logger, ILoggerFactory 等-->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
            </dependency>
            
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <type>test-jar</type>
                <version>${project.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
    </project>
    
    详细流程
    • step1:入口
    public class LogDemo {
        public static void main(String[] args) {
            Logger logger = LoggerFactory.getLogger(LogDemo.class); //断点处
            logger.info("log");
            System.out.println("log test");
        }
    }
    
    • Step2:中间跳过与上一篇文章相同之处,进入寻找 StaticLoggerBinder.class方法
    // We need to use the name of the StaticLoggerBinder class, but we can't
    // reference
    // the class itself.
    private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
    
    static Set<URL> findPossibleStaticLoggerBinderPathSet() {
        // use Set instead of list in order to deal with bug #138
        // LinkedHashSet appropriate here because it preserves insertion order
        // during iteration
        Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
        try {
            ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
            Enumeration<URL> paths;
            if (loggerFactoryClassLoader == null) {
                paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
            } else {
                //此处是关键能找到 StaticLoggerFactory.class 文件
                //file:/D:/local/mvnrepo/org/slf4j/slf4j-simple/1.7.25/slf4j-simple-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class
                //paths.size() == 1
                paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
            }
            while (paths.hasMoreElements()) {
                URL path = paths.nextElement();
                staticLoggerBinderPathSet.add(path);
            }
        } catch (IOException ioe) {
            Util.report("Error getting resources from path", ioe);
        }
        //携带者StaticLoogerBinder.class URL 返回
        return staticLoggerBinderPathSet;
    }
    
    • Step3:进入bind()
    private final static void bind() {
        try {
            Set<URL> staticLoggerBinderPathSet = null;
            // skip check under android, see also
            // http://jira.qos.ch/browse/SLF4J-328
            if (!isAndroid()) {
                //Step2 中已经找到,向下执行
                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
                reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            }
            // the next line does the binding
            //因为Step2 中明确已经找到 StaticLoggerBinder class,故此时不会抛异常,进入getSingleton()
            StaticLoggerBinder.getSingleton();
            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
            reportActualBinding(staticLoggerBinderPathSet);
            fixSubstituteLoggers();
            replayEvents();
            // release all resources in SUBST_FACTORY
            SUBST_FACTORY.clear();
        } catch (NoClassDefFoundError ncde) {
            String msg = ncde.getMessage();
            if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
                INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
                Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
                Util.report("Defaulting to no-operation (NOP) logger implementation");
                Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
            } else {
                failedBinding(ncde);
                throw ncde;
            }
        } catch (java.lang.NoSuchMethodError nsme) {
            String msg = nsme.getMessage();
            if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
                INITIALIZATION_STATE = FAILED_INITIALIZATION;
                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 nsme;
        } catch (Exception e) {
            failedBinding(e);
            throw new IllegalStateException("Unexpected initialization failure", e);
        }
    }
    
    • Step4:进入StaticLoggerBinder.getSingleton()
      • StaticLoggerBinder 定义于slf4j-simple.jar 中
    package org.slf4j.impl; //slf4j-api.jar 中定义的static StaticLoggerBinder.class 包路径
    
    import org.slf4j.ILoggerFactory; //slf4j-api的包
    import org.slf4j.spi.LoggerFactoryBinder;  //slf4j-api的包
    
    public class StaticLoggerBinder implements LoggerFactoryBinder {
    
        //这里用了饿汉单例模式生成 StaticLoggerBinder 类的实例
        private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
        public static String REQUESTED_API_VERSION = "1.6.99";
        private static final String loggerFactoryClassStr = SimpleLoggerFactory.class.getName();
        
        //每个StaticLoggerBinder 绑定了一个 ILoggerFactory 用以返回具体的 LoggerFactory 此处绑定的是 SimpleLoggerFactory
        private final ILoggerFactory loggerFactory = new SimpleLoggerFactory();
    
        //返回 StaticLoggerBinder 单例
        public static final StaticLoggerBinder getSingleton() {
            return SINGLETON;
        }
    
        private StaticLoggerBinder() {
        }
    
        //返回日志工厂
        public ILoggerFactory getLoggerFactory() {
            return this.loggerFactory;
        }
    
        public String getLoggerFactoryClassStr() {
            return loggerFactoryClassStr;
        }
    }
    
    • Step5:返回 bind 方法
    private final static void bind() {
        try {
            Set<URL> staticLoggerBinderPathSet = null;
            // skip check under android, see also
            // http://jira.qos.ch/browse/SLF4J-328
            if (!isAndroid()) {
                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
                reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            }
            // the next line does the binding
            //成功执行
            StaticLoggerBinder.getSingleton();
            // INITIALIZATION_STATE 赋值成功
            // bind 结束
            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
            reportActualBinding(staticLoggerBinderPathSet);
            fixSubstituteLoggers();
            replayEvents();
            // release all resources in SUBST_FACTORY
            SUBST_FACTORY.clear();
        } catch (NoClassDefFoundError ncde) {
            String msg = ncde.getMessage();
            if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
                INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
                Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
                Util.report("Defaulting to no-operation (NOP) logger implementation");
                Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
            } else {
                failedBinding(ncde);
                throw ncde;
            }
        } catch (java.lang.NoSuchMethodError nsme) {
            String msg = nsme.getMessage();
            if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
                INITIALIZATION_STATE = FAILED_INITIALIZATION;
                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 nsme;
        } catch (Exception e) {
            failedBinding(e);
            throw new IllegalStateException("Unexpected initialization failure", e);
        }
    }
    
    • Step:返回 performInitialization
    private final static void performInitialization() {
        bind();
        if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
            versionSanityCheck();
        }
    }
    
    • Step:返回 getILoggerFactory()
    public static ILoggerFactory getILoggerFactory() {
        if (INITIALIZATION_STATE == UNINITIALIZED) {
            synchronized (LoggerFactory.class) {
                if (INITIALIZATION_STATE == UNINITIALIZED) {
                    INITIALIZATION_STATE = ONGOING_INITIALIZATION;
                    //执行结束
                    performInitialization();
                }
            }
        }
        //进入switch 
        switch (INITIALIZATION_STATE) {
        //此时INITIALIZATION_STATE 成功初始化
        case SUCCESSFUL_INITIALIZATION:
            //拿到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://jira.qos.ch/browse/SLF4J-97
            return SUBST_FACTORY;
        }
        throw new IllegalStateException("Unreachable code");
    }
    
    • Step:
    public static Logger getLogger(String name) {
        //取得LoggerFactory
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        //通过LoggerFactory 得到具体日志框架
        return iLoggerFactory.getLogger(name);
    }
    
    • Step:返回main
        public static void main(String[] args) {
            Logger logger = LoggerFactory.getLogger(LogDemo.class);
            logger.info("log");
    
            URL ls = Logger.class.getClassLoader().getResource("org/slf4j/Logger.class");
            System.out.println("log test");
        }
    

    相关文章

      网友评论

          本文标题:Slf4j 源码解析二-添加 slf4j-simple 日志实现

          本文链接:https://www.haomeiwen.com/subject/roketftx.html