slf4j如何绑定到实现?在编译期间它真的这样做了吗?

时间:2013-07-24 09:23:54

标签: slf4j

在slf4j的文档中,它说绑定发生在complie time:

“SLF4J不依赖于任何特殊的类加载器机制。实际上,每个SLF4J绑定在编译时都是硬连线使用一个且只有一个特定的日志框架。例如,slf4j-log4j12-1.7.5.jar绑定在编译时绑定使用log4j。在你的代码中,除了slf4j-api-1.7.5.jar之外,你只需将你选择的一个绑定只删除到相应的类路径位置。不要放置多个绑定在类路径上。这是一般想法的图解说明。“ http://www.slf4j.org/manual.html

这是如何运作的?

6 个答案:

答案 0 :(得分:5)

这是slf4j的源代码。  Slf4j将在类路径中找到路径为“ org / slf4j / impl / StaticLoggerBinder.class ”的所有类。如果有多个,jvm将只随机选取一个。有关详细信息,请参阅此处:http://www.slf4j.org/codes.html#multiple_bindings

// We need to use the name of the StaticLoggerBinder class, but we can't
// reference
// the class itself.

private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

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;
}

答案 1 :(得分:4)

这也是我的问题,我想添加我的答案,因为发现另外两个答案不够清楚(虽然完全正确)。

首先,在LoggerFactory.bind()link

slf4j-api的实施中检查此行
// the next line does the binding
StaticLoggerBinder.getSingleton();

有一个名为org.slf4j.impl.StaticLoggerBinder的班级。检查github上的实施情况。

现在继续从中央maven存储库下载slf4j-api.jar,解压缩并找到StaticLoggerBinder.class文件。

不要试试!你不能。实际上整个org.slf4j.impl已从包中删除。检查项目的pom.xml

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
      <execution>
        <phase>process-classes</phase>
        <goals>
         <goal>run</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <tasks>
        <echo>Removing slf4j-api's dummy StaticLoggerBinder and StaticMarkerBinder</echo>
        <delete dir="target/classes/org/slf4j/impl"/>
      </tasks>
    </configuration>
  </plugin>

最后,检查一个SLF4j的绑定包,例如slf4j-simple。你能找到org.slf4j.impl.StaticLoggerBinder班吗?

总而言之,当您在运行时环境中只有一个(且仅一个)绑定包时,slf4j-api.jar只有一个org.slf4j.impl.StaticLoggerBinder类来执行绑定。

答案 2 :(得分:3)

从我所看到的,它通过期望StaticLoggingBinder类在同一个包(org.slf4j.impl)中来实现这一点,无论实现如何 - 所以它总是在同一个地方找到它。

答案 3 :(得分:0)

从技术上讲,没有魔法和#34;绑定&#34;发生在编译时。 &#34;绑定&#34;当SLF4J开发人员创建库来处理最流行的Java日志框架时,就发生了这种情况。

当文档说&#34;绑定在编译时被硬连线时,&#34;这意味着SLF4J开发人员已经为特定的Java日志框架创建了一个目标库。 SLF4J具有专用于Java Logging,Jakarta Commons Logging,Log4J和控制台输出的库。您需要在运行时只包含这些库中的一个,以便SLF4J成功创建日志消息。

有关SLF4J如何工作的更多信息:A more visual way to understand SLF4J

答案 4 :(得分:0)

就像@Rad所说的那样。

我想补充的是,如果您在运行时环境中有多个StaticLoggerBinder实现,则slf4j选择其中一个 RANDOMLY ,如multiple_bindings中所述:

  

SLF4J选择绑定的方式由JVM确定,出于所有实际目的,应将其视为随机的。从1.6.6版开始,SLF4J将为其实际绑定的框架/实现类命名。

另一个注意事项是,如果计划将您的项目作为其他项目的库,则仅应包含slf4j-api,不允许对slf4j-api进行任何实现:

  

诸如库或框架之类的嵌入式组件不应声明对任何SLF4J绑定的依赖,而只能依赖slf4j-api。当一个库声明对SLF4J绑定的编译时依赖性时,它将该绑定强加给最终用户,从而否定了SLF4J的目的。

答案 5 :(得分:0)

实现在编译时未绑定(它不是静态/早期绑定),换句话说,是在编译时未知的实现

实际上,反之亦然,在运行时绑定实现,这意味着通过动态/运行时绑定发现实现。 Slf4j员工实际上已经在他们的手册https://www.slf4j.org/manual.html中声明了绑定是如何发生的:

  

SLF4J允许最终用户在部署时插入所需的日志记录框架。