SLF4J / JPA / JAX-RS如何找到它们的实现?

时间:2017-02-12 11:17:16

标签: java logging slf4j

我正在学习Java,我发现有很多标准化的功能:

  • 记录(使用SLF4J)
  • 持久性(使用JPA)
  • REST(使用JAX-RS)
  • SOAP(使用JAX-WS)

让我们看一下Sl4j示例:要正确使用log4j,我们必须导入sl4j api,sl4j / log4j桥和log4j实现。

问题:在我的班级中,我只与Slf4j API进行通信。

我的应用程序如何知道log4j实现? 有人可以解释一下究竟发生了什么吗?

此致

4 个答案:

答案 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-apihibernate-*(核心,实体管理员等)。

假设您要创建EntityManagerFactory

    import javax.persitence.EntityManagerFactory
    import javax.persitence.Persistence;
    ...
    private static EntityManagerFactory EMF = Peristence.createEntityManagerFactory("foobar", null);

对于ListArrayList,您的类路径由于您导入的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所示:

enter image description here

答案 2 :(得分:2)

Slf4j可与log4j或任何其他基础日志记录库一起使用。

如果是log4j,则会使用log4j-slf4j-impl.jar,其中包含与log4j库进行通信所必需的类。

根据documentation -

  

SLF4J在执行时不解析日志记录实现,但是   直接在编译时使用桥接API。所以比JAR更多   SLF4J你需要以下JAR:桥接JAR和JAR   实施。以下是Log4J的内容:

Slf4j-log4j Integration

答案 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不是为在运行时选择实现而设计的。