slf4j 运行原理
slf4j组件对外提供统一的日志对象访问接口,log4j,logback这类组件会实现这个接口中的相关标准规定,下面分为几步详细说下怎么实现。
1.先调用slf4j组件的方法 Logger logger = LoggerFactory.getLogger(App.class);
2.调用slf4j组件的 getILoggerFactory()方法开始获取具体的实现类log4j;
3.getILoggerFactory会调用bind方法,bind会再调用findPossibleStaticLoggerBinderPathSet()方法尝试获取实现了标准的类,loggerFactoryClassLoader.getResources("org/slf4j/impl/StaticLoggerBinder.class") 会去classpath查找这个类,如果有,说明项目引入了具体的日志组件,可以进行日志的记录,这是会返回具体的对象,否则就会提示没有找到相关的类;
4.获取到具体对象后(这里是Log4jLoggerFactory),会调用该对象的getLogger方法,获取到具体的日志对象,至此,开始输出日志,程序结束。
代码
//Logger logger = LoggerFactory.getLogger(Object.class); 通过LoggerFactory去拿slf4j提供的一个Logger接口的具体实现 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; } //LoggerFactory的bind()方法 private final static void bind() { try { SetstaticLoggerBinderPathSet = null; 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); } } //这个地方重点其实就是第12行的代码,getLogger的时候会去classpath下找STATIC_LOGGER_BINDER_PATH, //STATIC_LOGGER_BINDER_PATH值为"org/slf4j/impl/StaticLoggerBinder.class",即所有slf4j的实现,在提供的jar包路径下, //一定是有"org/slf4j/impl/StaticLoggerBinder.class"存在的 static SetfindPossibleStaticLoggerBinderPathSet() { // use Set instead of list in order to deal with bug #138 // LinkedHashSet appropriate here because it preserves insertion order // during iteration SetstaticLoggerBinderPathSet = new LinkedHashSet(); try { ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader(); Enumerationpaths; 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; }
版权声明:本文为JAVASCHOOL原创文章,未经本站允许不得转载。