slf4j如何将sfl4j-api中的org.slf4j.impl.StaticLoggerBinder替换为真正的StaticLoggerBinder

时间:2012-08-31 21:22:32

标签: java classloader slf4j

在slf4j api中存在类org.slf4j.impl.StaticLoggerBinder,org.slf4j.impl.StaticMarkerBinder,org.slf4j.impl.StaticMDCBinder。但是每个绑定到具体记录器的应该包含相同的类。

例如:

http://grepcode.com/file/repo1.maven.org/maven2/org.slf4j/slf4j-api/1.6.1/org/slf4j/impl/StaticLoggerBinder.java?av=f

及其log4j实现: http://grepcode.com/file/repo1.maven.org/maven2/org.slf4j/slf4j-log4j12/1.6.1/org/slf4j/impl/StaticLoggerBinder.java?av=f

java类加载器如何替代它?这不应该是一个例外吗?

2 个答案:

答案 0 :(得分:3)

如果您提取实际的slf4j-api jar,您会注意到org.slf4j.impl.StaticLoggerBinder实际上并未包含在jar中。 SFL4J api是在构建时针对类编译的,但它实际上并未包含在工件中。如果你在api模块中查看org.slf4j.impl.StaticLoggerBinder的源代码,它没有实现,所有公共实例方法抛出UnsupportedOperationException。这没关系,因为该类被排除在slf4j-api jar之外。

类加载器行为正常,并选择在需要加载类时找到的org.slf4j.impl.StaticLoggerBinder的第一个版本。这通常来自它在类路径中列出的第一个slf4j实现jar。

注意: findPossibleStaticLoggerBinderPathSet()仅用于警告类路径上存在多个绑定。它实际上并没有加载任何绑定。

答案 1 :(得分:1)

嗯,好的问题是slf4j假设不使用运行时加载类。它看起来在启动时使用类加载器检查以下方法:

private static Set findPossibleStaticLoggerBinderPathSet() {
    // use Set instead of list in order to deal with  bug #138
    // LinkedHashSet appropriate here because it preserves insertion order during iteration
    Set 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 ioe) {
      Util.report("Error getting resources from path", ioe);
    }
    return staticLoggerBinderPathSet;
}

@Dev是对的 - org.slf4j.impl.StaticLoggerBinder仅包含在slf4j-api源中而不包含在二进制文件中 - 由于编译原因,仅包含在源代码中是一个简单的技巧。可以理解,findPossibleStaticLoggerBinderPathSet仅用于记录目的。