1.slf4j source code analysis
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private Logger log = LoggerFactory.getLogger(this.getClass());
1.1 getLogger analytical method
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 " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
}
}
return logger;
}
After half of the logic: When passed in class and the caller's name clazz whether to print a warning inconsistent information (default is not printed),
1.2getLogger specific implementation method:
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
Acquiring a corresponding class factory implementation by getILoggerFactory, then acquires the corresponding log object
Detailed methods 1.3getILoggerFactory
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
}
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
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");
}
First execution performInitialization initialized into operation according to different values of INITIALIZATION_STATE (initialized successfully used to return a factory class, which in turn acquires a corresponding log object)
1.4performInitialization Method Description
private final static void performInitialization() {
bind();
if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
versionSanityCheck();
}
}
Methods bind to the actual performInitialization, versionSanityCheck just took jdk version checking, not described in detail again
1.5bind
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 = 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);
}
}
bind key method
findPossibleStaticLoggerBinderPathSet (); - Looking for binding path
StaticLoggerBinder.getSingleton (); - obtaining binding factory method
fixSubstituteLoggers (); - did not understand what the role is, there is hope to see the next big brother pointing
replayEvents (); - did not understand what the role is, there are big brothers to see under the guidance of hope
1.5.1findPossibleStaticLoggerBinderPathSet
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 {
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);
}
return staticLoggerBinderPathSet;
}
Get all org / slf4j / impl class path StaticLoggerBinder.class / (a warning when the acquisition is larger than but only warnings do not affect the operation)
See the official documentation:
The warning emitted by SLF4J is just that, a warning. Even when multiple bindings are present, SLF4J will pick one logging
framework/implementation and bind with it. The way SLF4J picks a
binding is determined by the JVM and for all practical purposes should
be considered random. As of version 1.6.6, SLF4J will name the
framework/implementation class it is actually bound to.
Embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on
slf4j-api. When a library declares a compile-time dependency on a
SLF4J binding, it imposes that binding on the end-user, thus negating
SLF4J’s purpose. When you come across an embedded component declaring
a compile-time dependency on any SLF4J binding, please take the time
to contact the authors of said component/library and kindly ask them
to mend their ways.
1.5.2 (slf4j key)
StaticLoggerBinder class using a class that is found in all paths findPossibleStaticLoggerBinderPathSet (particularly jvm loaded classes according to the order, the order according to Experiment I obtained is the reference sequence jar, for example, while introducing slf4j-nop. jar slf4j-simple.jar, slf4j-log4j12.jar , slf4j-jdk14.jar, logback-classic.jar, uses slf4j-nop.jar in StaticLoggerBinder to obtain a corresponding class factory)
As slf4j-api. StaticLoggerBinder source code in fact, the class played a jar slf4j-api.jar is non-existent because of his pom file written, when packaging will remove the source code directory and its impl next file.
1.5.3 reportActualBinding
output StaticLoggerBinder actual (binding) used