为什么要使用 slf4j
现实场景:
我们自己的系统中使用了 logback 这个日志系统
我们的系统使用了 A.jar,A.jar 中使用的日志系统为 log4j
我们的系统又使用了 B.jar,B.jar 中使用的日志系统为 slf4j-simple
这样, 我们的系统就不得不同时支持并维护 logback,log4j,slf4j-simple 三种日志框架, 非常不便.
解决这个问题的方式就是引入一个适配层, 由适配层决定使用哪一种日志系统, 而调用端只需要做的事情就是打印日志而不需要关心如何打印日志, slf4j 或者 commons-logging 就是这种适配层.
从上面的描述, 我们清楚地知道一点: slf4j 只是一个日志标准, 并不是日志系统的具体实现.
理解这句话非常重要, slf4j 只做两件事情:
提供日志接口
提供获取具体日志对象的方法
slf4j-simple,logback-classic 都是 slf4j 的具体实现, log4j 并不直接实现 slf4j, 但是有专门的一层桥接 slf4j-log4j12 来实现 slf4j.
slf4j 实现原理
slf4j 的用法就是一句 "Logger logger = LoggerFactory.getLogger(Object.class);"
可见这里就是通过 LoggerFactory 去拿 slf4j 提供的一个 Logger 接口的具体实现而已. getLogger 的时候会去 classpath 下找 STATIC_LOGGER_BINDER_PATH, 即所有 slf4j 的实现, 在提供的 jar 包路径下, 一定是有 "org/slf4j/impl/StaticLoggerBinder.class" 存在的.
- private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
- 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 = paths.nextElement();
- staticLoggerBinderPathSet.add(path);
- }
- } catch (IOException ioe) {
- Util.report("Error getting resources from path", ioe);
- }
- return staticLoggerBinderPathSet;
- }
我们不能避免在系统中同时引入多个 slf4j 的实现, 所以接收的地方是一个 Set.
同时存在多个 "org/slf4j/impl/StaticLoggerBinder.class" 怎么办?
首先确定的是这不会导致启动报错只会打印 warnning, 其次在这种情况下编译期间, 编译器会选择其中一个 StaticLoggerBinder.class 进行绑定, sfl4j 也在 reportActualBinding 方法中报告了绑定的是哪个日志框架.
StaticLoggerBinder 就比较简单了, 不同的 StaticLoggerBinder 其 getLoggerFactory 实现不同, 拿到 ILoggerFactory 之后调用一下 getLogger 即拿到了具体的 Logger, 可以使用 Logger 进行日志输出.
来源: http://www.bubuko.com/infodetail-2554351.html