“SLF4J 日志绑定原理”的版本间的差异
		
		
		
		
		
		跳到导航
		跳到搜索
		
				
		
		
	
Jihongchang(讨论 | 贡献)  | 
				Jihongchang(讨论 | 贡献)   | 
				||
| (未显示同一用户的2个中间版本) | |||
| 第122行: | 第122行: | ||
-> LoggerFactory.bind()  | -> LoggerFactory.bind()  | ||
| + | |||
| + | -> LoggerFactory.findPossibleStaticLoggerBinderPathSet()<syntaxhighlight lang="java">  | ||
| + |     private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";  | ||
| + | |||
| + |     static Set<URL> findPossibleStaticLoggerBinderPathSet() {  | ||
| + |         Set<URL> 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;  | ||
| + |     }  | ||
| + | </syntaxhighlight>org.slf4j.impl.StaticLoggerBinder.java<syntaxhighlight lang="java">  | ||
| + | package org.slf4j.impl;  | ||
| + | ……  | ||
| + | public class StaticLoggerBinder implements LoggerFactoryBinder {  | ||
| + | ……  | ||
| + |     private final ILoggerFactory loggerFactory = new JDK14LoggerFactory();  | ||
| + | ……  | ||
| + | }  | ||
| + | </syntaxhighlight>JDK14LoggerFactory.java<syntaxhighlight lang="java">  | ||
| + | package org.slf4j.impl;  | ||
| + | ……  | ||
| + | public class JDK14LoggerFactory implements ILoggerFactory {  | ||
| + | ……  | ||
| + |     public JDK14LoggerFactory() {  | ||
| + |         java.util.logging.Logger.getLogger("");  | ||
| + |     }  | ||
| + | ……  | ||
| + | }  | ||
| + | </syntaxhighlight>  | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | === SLF4J 原理解析 ===  | ||
| + | |||
| + | # SLF4J 通过 LoggerFactory 加载日志具体的实现对象  | ||
| + | # LoggerFactory 在初始化的过程中,会通过 performInitialization() 方法绑定具体的日志实现  | ||
| + | # 在绑定具体的日志实现的时候,通过类加载器,加载 org/slf4j/impl/StaticLoggerBinder.class  | ||
| + | # 所以,只要是一个日志实现框架,在 org.slf4j.impl 包中提供一个自己的 StaticLoggerBinder 类,在其中提供具体日志实现的 LoggerFactory 就可以被 SLF4J 加载  | ||
2023年2月27日 (一) 02:39的最新版本
https://www.bilibili.com/video/BV1iJ411H74S?p=24
源码跟踪
SLF4JTest.java
……
public class SLF4JTest {
    public static final Logger LOGGER = LoggerFactory.getLogger(SLF4JTest.class);
    ……
}
LoggerFactory.java
……
public final class LoggerFactory {
    ……
    public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }
    public static Logger getLogger(Class<?> clazz) {
        Logger logger = getLogger(clazz.getName());
        if (DETECT_LOGGER_NAME_MISMATCH) {
            Class<?> autoComputedCallingClass = Util.getCallingClass();
            if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(), autoComputedCallingClass.getName()));
                Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
            }
        }
        return logger;
    }
    ……
    public static ILoggerFactory getILoggerFactory() {
        if (INITIALIZATION_STATE == 0) {
            Class var0 = LoggerFactory.class;
            synchronized(LoggerFactory.class) {
                if (INITIALIZATION_STATE == 0) {
                    INITIALIZATION_STATE = 1;
                    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:
                return StaticLoggerBinder.getSingleton().getLoggerFactory();
            case 4:
                return NOP_FALLBACK_FACTORY;
            default:
                throw new IllegalStateException("Unreachable code");
        }
    }
    ……
    private static final void performInitialization() {
        bind();
        if (INITIALIZATION_STATE == 3) {
            versionSanityCheck();
        }
    }
    ……
    private static final void bind() {
        String msg;
        try {
            Set<URL> staticLoggerBinderPathSet = null;
            if (!isAndroid()) {
                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
                reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            }
            StaticLoggerBinder.getSingleton();
            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);
        }
    }
    ……
}
调用顺序:LoggerFactory.getLogger(Class<?> clazz)
-> LoggerFactory.getLogger(String name)
-> LoggerFactory.getILoggerFactory()
-> LoggerFactory.performInitialization()
-> LoggerFactory.bind()
-> LoggerFactory.findPossibleStaticLoggerBinderPathSet()
    private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
    static Set<URL> findPossibleStaticLoggerBinderPathSet() {
        Set<URL> 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;
    }
org.slf4j.impl.StaticLoggerBinder.java
package org.slf4j.impl;
……
public class StaticLoggerBinder implements LoggerFactoryBinder {
……
    private final ILoggerFactory loggerFactory = new JDK14LoggerFactory();
……
}
JDK14LoggerFactory.java
package org.slf4j.impl;
……
public class JDK14LoggerFactory implements ILoggerFactory {
……
    public JDK14LoggerFactory() {
        java.util.logging.Logger.getLogger("");
    }
……
}
SLF4J 原理解析
- SLF4J 通过 LoggerFactory 加载日志具体的实现对象
 - LoggerFactory 在初始化的过程中,会通过 performInitialization() 方法绑定具体的日志实现
 - 在绑定具体的日志实现的时候,通过类加载器,加载 org/slf4j/impl/StaticLoggerBinder.class
 - 所以,只要是一个日志实现框架,在 org.slf4j.impl 包中提供一个自己的 StaticLoggerBinder 类,在其中提供具体日志实现的 LoggerFactory 就可以被 SLF4J 加载