在slf4j的文档中,它说绑定发生在complie time:
“SLF4J不依赖于任何特殊的类加载器机制。实际上,每个SLF4J绑定在编译时都是硬连线使用一个且只有一个特定的日志框架。例如,slf4j-log4j12-1.7.5.jar绑定在编译时绑定使用log4j。在你的代码中,除了slf4j-api-1.7.5.jar之外,你只需将你选择的一个绑定只删除到相应的类路径位置。不要放置多个绑定在类路径上。这是一般想法的图解说明。“ http://www.slf4j.org/manual.html
这是如何运作的?
答案 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允许最终用户在部署时插入所需的日志记录框架。