源码分析slf4j和logback的关系
来源:互联网 发布:软件研制过程概述 编辑:程序博客网 时间:2024/05/16 10:05
slf4j是几种日志框架的api框架,提供了几种常用日志框架的接口规范。如果在项目中引入了下面的依赖即可:
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.3</version> </dependency>
logback会依赖传递进来slfj4j的api包。项目启动时走读一下源码,首先通过 private static final Logger logger= LoggerFactory.getLogger(xx.class);获取logger。这里的调用暂时都是走在slfj4-api包里面的。参数传递的是类,实际会调用获取类name的重载函数如下:
public static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); }
getILoggerFactory方法如下:
public static ILoggerFactory getILoggerFactory() { 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://bugzilla.slf4j.org/show_bug.cgi?id=106 return TEMP_FACTORY; } throw new IllegalStateException("Unreachable code"); }
一般情况下performInitialization()这个日志工厂初始化方法已经被提前调用了,为什么呢,这个初始化方法只会在第一次调用getILoggerFactory()被调用,因为你的项目中引入的别的常用框架在启动的时候可能会第一次调用了这个方法。比如较新颁布的spring框架等等。
如果是第一次调用,进入初始化方法看一下:
private final static void bind() { try { Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();//寻找真实日志绑定类路径 reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); // the next line does the binding StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; reportActualBinding(staticLoggerBinderPathSet); fixSubstitutedLoggers(); } 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.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) { 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()方法,为什么叫bind不叫 init之类的呢。其实这个方法最重要是做了从日志api框架到真实实现的logback和log4j的绑定。这个方法里面调用的第一个方法findPossibleStaticLoggerBinderPathSet()是寻找到真实的日志绑定类。进入如下:
private 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 = (URL) paths.nextElement(); staticLoggerBinderPathSet.add(path); } } catch (IOException ioe) { Util.report("Error getting resources from path", ioe); } return staticLoggerBinderPathSet; }
首先获取类加载器,这个获取的是WebAppClassLoader。为什么会是这个类加载器,这个加载器的作用是啥?先看一下tomcat的类加载器树。
java的类加载是采用双亲委派机制,默认只能从下往上,不过有几种方法可以破坏双亲委派机制,实现更高层的加载器调用更加低层的加载器的方式。不过不是本文的重点。如果是从jsp的类加载器就从 jasperLoader开始。本文中的类获取加载器时向上检索,第一个获取的是webAppClassLoader类加载器。这个类加载器的默认类文件检索范围是整个web应用(不包括依赖的所有可以由更高层类加载器加载的类)。然后调用
ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH)//STATIC_LOGGER_BINDER_PATH的值是org/slf4j/impl/StaticLoggerBinder.class
最终获取类文件的url路径 jar:file:/Users/XXX/Work/apache-tomcat-7.0.64/webapps/ROOT/WEB-INF/lib/logback-classic-1.1.3.jar!/org/slf4j/impl/StaticLoggerBinder.class
StaticLoggerBinder是logback的一个绑定类,该类实现了slf4j的LoggerFactoryBinder的接口。
最后StaticLoggerBinder.getSingleton()在StaticLoggerBinder的init()方法里完成了对logback的工厂类LoggerContext(实现了ILoggerFactory)的初始化,包括从配置文件如logback.xml里面加载配置信息。完成了整个logger工厂的初始化。未完待续
- 源码分析slf4j和logback的关系
- slf4j、logback和log4j的关系
- slf4j和log4j、logback的关系
- slf4j logback log4j的关系
- Slf4j MDC 使用和 基于 Logback 的实现分析
- log4j+logback+slf4j的关系与调试
- log4j+logback+slf4j的关系与调试
- log4j,logback,slf4j三者的关系
- log4j+logback+slf4j的关系与调试
- log4j+logback+slf4j+commons-loggin的关系
- log4j,logback,slf4j之间的关系详解
- log4j+logback+slf4j的关系与调试
- slf4j和logback的组合使用(一)
- slf4j和logback的详细使用(二)
- logback和slf4j的使用chapter2
- logback和slf4j的使用chapter3
- slf4j 和 logback-classic遇到的坑
- slf4j log4j logback关系详解和相关用法
- python学习——获取对象信息
- Git命令简明清晰版
- 报java.lang.NullPointerException原因
- 深入理解asp.net里的HttpModule机制
- 关于SQL Server/oracle将一列的多行内容拼接成一行的问题讨论
- 源码分析slf4j和logback的关系
- 想成为嵌入式程序员应知道的0x10个基本问题
- C++ 类定义与操作
- 《增广贤文》辑注
- 最大子序列和最大递增子序列
- Android中直播视频技术探究之---基础核心类ByteBuffer解析
- python学习——实例属性和类属性
- 网络连接不上的问题处理
- android multimedia的代码边读边记