我正在学习Java,我发现有很多标准化的功能:
让我们看一下Sl4j示例:要正确使用log4j,我们必须导入sl4j api,sl4j / log4j桥和log4j实现。
问题:在我的班级中,我只与Slf4j API进行通信。
我的应用程序如何知道log4j实现? 有人可以解释一下究竟发生了什么吗?
此致
答案 0 :(得分:4)
OP提出了一个关于如何在某些不同情况下注入实现的一般性问题。
正如许多答案所述,SLF4J
给出了界面,log4j-slf4j
给出了实现。
使用以下语句时:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
private static final Logger LOG = LoggerFactory.getLogger(FooBarClass.class);
...
LOG.debug("Foobar");
这就是发生的事情:
我们尝试从LoggerFactory
class中声明的Logger
方法中获取getLogger
:
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
}
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
}
...
}
所以神奇的事情发生在那句话上:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
因为类路径知道你实现了原因,StaticLoggerBinder
实现is provided by log4j
。
我们可以注意到,log4j
提供了自己的实现:
private final ILoggerFactory loggerFactory;
...
private StaticLoggerBinder() {
loggerFactory = new Log4jLoggerFactory();
}
就是这样!
对于JPA / Hibernate部分,您必须包含hibernate-jpa-api
和hibernate-*
(核心,实体管理员等)。
假设您要创建EntityManagerFactory
:
import javax.persitence.EntityManagerFactory
import javax.persitence.Persistence;
...
private static EntityManagerFactory EMF = Peristence.createEntityManagerFactory("foobar", null);
对于List
和ArrayList
,您的类路径由于您导入的JAR而提供了接口和实现。
EntityManagerFactory
来自hibernate-jpa-api
我们有Persistence
class的地方。
我们可以注意到,createEntityManagerFactory
方法首先列出了所有提供商,并且对于每个提供商,都会触发createEntityManagerFactory
。
这是hibernate
的来源。它提供HibernatePersistenceProvider
implements the PersistenceProvider
class。
这是注射Hibernate
的方式。
答案 1 :(得分:2)
如果您正在谈论处理slf4j
记录器,例如:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FooClass.class);
然后它很简单:org.slf4j.Logger
只是一个接口,它有几个实现。对于使用库slf4j-log4j12
,此接口由类org.slf4j.impl.Log4jLoggerAdapter
实现,内部包含
final transient org.apache.log4j.Logger logger;
因此,它是简单的适配器,它包装您的日志记录请求并在log4j
logger对象上调用它们:
public void debug(String msg) {
logger.log(FQCN, Level.DEBUG, msg, null);
}
更具体地说,Logger
生成了LoggerFactory
正确的实施方式,首先通过
Log4jLoggerFactory
StaticLoggerBinder.getSingleton().getLoggerFactory()
,后者创建了所需的Log4jLoggerAdapter
实例。
一般情况下,它通过适应级别工作,如documentation上的img所示:
答案 2 :(得分:2)
Slf4j
可与log4j
或任何其他基础日志记录库一起使用。
如果是log4j
,则会使用log4j-slf4j-impl.jar
,其中包含与log4j
库进行通信所必需的类。
根据documentation -
SLF4J在执行时不解析日志记录实现,但是 直接在编译时使用桥接API。所以比JAR更多 SLF4J你需要以下JAR:桥接JAR和JAR 实施。以下是Log4J的内容:
答案 3 :(得分:1)
SLF4J手册指的是SLF4J如何找到要使用的实现:Binding with a logging framework at deployment time。
SLF4J指的是允许使用实现(Logback,Log4J等)作为" SLF4J绑定" :
如前所述,SLF4J支持各种日志框架。 SLF4J发行版附带了几个jar文件 " SLF4J绑定",每个绑定对应一个受支持的绑定 框架。
您拥有与SLF4J实现一样多的SLF4J绑定。 当然,实现API可能具有不同的" SLF4J绑定"根据其版本:
要切换日志框架,只需替换你的slf4j绑定即可 阶级路径。例如,要从java.util.logging切换到log4j, 只需用slf4j-log4j12-1.7.22.jar替换slf4j-jdk14-1.7.22.jar。
与实现的绑定不是在运行时执行,而是在编译时执行:每个SLF4J绑定在编译时都是硬连线的,以使用一个且只有一个特定的日志记录框架。
因此,您只需在类路径中包含SLF4J绑定(例如slf4j-jdk14-1.7.22.jar),以便SLF4J使用它:
SLF4J不依赖任何特殊的类装载机械。事实上, 每个SLF4J绑定在编译时都是硬连线的,只能使用一个 一个特定的日志框架。例如, slf4j-log4j12-1.7.22.jar绑定在编译时绑定使用 log4j的。在您的代码中,除了slf4j-api-1.7.22.jar之外,您还可以 将您选择的一个且仅一个绑定放到适当的绑定上 类路径位置。不要在课堂上放置多个装订 路径。以下是一般概念的图解说明。
这就是为什么通常建议不要在类路径上放置多个SLF4J绑定,因为SLF4J不是为在运行时选择实现而设计的。