对使用 Spring 和 Hibernate 的 Java 日志系统感到困惑

Posted

技术标签:

【中文标题】对使用 Spring 和 Hibernate 的 Java 日志系统感到困惑【英文标题】:Baffled by Java Logging Systems with Spring and Hibernate 【发布时间】:2011-01-07 23:21:33 【问题描述】:

在部署我的 Spring / Hibernate 应用程序时,我收到以下与日志记录相关的警告:

log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
log4j:WARN Please initialize the log4j system properly.

令我惊讶的是,Google/SO 搜索中缺少信息。唯一相关的是这个 SO 帖子 Problem with Commons Logging / Log4j setup in spring webapp with tomcat 6

但是,这甚至超出了我的范围。有人可以在这里澄清正在使用的日志系统,或者指向我关于此事的最近资源(有一些古老的谷歌搜索结果并不真正适用)。具体来说,我正在努力解决的问题是:

commons-logging、log4j、slf4j 和 JCL 的区别。我的理解是 slf4j 是一个包装器,而 commons-logging 和 log4j 是实际的实现。我不知道 JCL 适合哪里。

如何为 Spring 配置日志记录。 web.xml 文件中有什么,我需要 log4j.properties 文件还是 log4j.xml 文件?在 WEB-INF 中它在哪里?我的 applicationContext.xml 文件中有什么内容吗? (对不起,我需要从零开始)。

我在我的项目中使用 Hibernate,包括通过 Maven。似乎 Hibernate 使用 slf4j-simple。我看到警告说我不能在类路径上同时拥有 slf4j-simple 和 slf4j-log4j。我没有包含 slf4j-log4j 作为依赖项,但 Hibernate 必须包含它。我该如何解决这个问题?我可以强制 Hibernate 使用 log4j 吗?

任何帮助将不胜感激。谢谢。


编辑:

感谢到目前为止的所有答案。我正在尝试这些建议。 spring web-app 具体怎么样?我已经看到了侦听器和参数的示例以及放入 web.xml 文件中的内容。这也需要吗?

【问题讨论】:

【参考方案1】: commons-logging 和 SLF4J 都是围绕其他日志记录实现的 API 包装器。 SLF4J 是两者中更现代的,而且功能更强大。 Log4j 是一个日志实现,几乎是事实上的标准。 JUL(java.util.logging 的缩写)是 JRE 附带的(通常很糟糕)日志记录实现。另一个日志实现是 logback,它正在慢慢获得关注,但还没有普及。 log4j.propertieslog4j.xml 是配置 log4j 的不同方式,两者同样有效。您使用哪一个取决于您,尽管某些应用程序服务器会指定其中一个。阅读log4j manual 了解如何配置它。 如果 Hibernate 使用 SLF4J 作为其 API,那是 Hibernate 开发人员的选择。但是,您可以选择 SLF4J 将委托给哪个日志记录实现。再次阅读slf4j manual,了解如何选择您选择的实现。

是的,这一切都相当混乱。给定一个开放的选择,SLF4J 和 Logback 是最有能力的组合,但你通常没有一个开放的选择。不同的框架(如 Hibernate 和 Spring)可能会使用不同的日志 API,通常是 commons-logging 或 SLF4J,但您可以让所有这些 API 最终记录到相同的底层实现(通常是 log4j)。

【讨论】:

【参考方案2】:
commons-logging、log4j、slf4j 和 JCL 之间的区别。我的理解是 slf4j 是一个包装器,而 commons-logging 和 log4j 是实际的实现。我不知道 JCL 适合哪里。

Jakarta Commons Logging (JCL) 和 Simple Logging Facade for Java SLF4J 都是各种日志框架抽象,例如java.util.logging、log4j 和 logback,允许最终用户在部署时插入所需的日志框架。众所周知,Commons Logging 存在类加载器问题,这是 SLF4J 试图解决的问题(众所周知,SLF4J 是一个更干净的库)。

话虽如此,事实上 Spring 使用 Jakarta Commons Logging API(参见 Logging Dependencies in Spring):Spring 是针对 JCL 编译的,Spring 使 JCL Log 对象可用于扩展 Spring 的类。实际上是 Spring 中唯一的强制外部依赖。这个选择has been made 因为许多其他框架也在使用它(例如 Struts)。这个想法是避免在构建应用程序时必须在类路径上有多个外观库(“A”代表 Spring,“B”代表 Struts 等)。但是,如果您愿意,可以用 SLF4J 替换 JCL(SFL4J 提供与日志框架的绑定,但也提供“JCL 到 SLF4J”的桥梁)。有关所有详细信息,请参阅提到的帖子Logging Dependencies in Spring。

如何为 Spring 配置日志记录。 web.xml 文件中有什么,我需要 log4j.properties 文件还是 log4j.xml 文件?在 WEB-INF 中它在哪里?我的 applicationContext.xml 文件中有什么内容吗? (抱歉,我这里需要从零开始)。

要记录,您有 1. 决定要使用哪种实现(java.util.logging、log4j 或 logback),2. 如果需要,将选择的实现放在类路径中(java.util.logging 在Java SE 所以它不需要额外的库)和 3. 配置它(通过将配置文件放在类路径上)。如果您选择使用 log4j,只需将其 jar 和 log4j.properties 或更花哨(但更冗长)log4j.xml(这只是配置的另一种格式)添加到类路径。

我在我的项目中使用 Hibernate,包括通过 Maven。似乎 Hibernate 使用 slf4j-simple。我看到警告说我不能在类路径上同时拥有 slf4j-simple 和 slf4j-log4j。我没有包含 slf4j-log4j 作为依赖项,但 Hibernate 必须包含它。我该如何解决这个问题?我可以强制 Hibernate 使用 log4j 吗?

Hibernate utilizes Simple Logging Facade for Java (SLF4J),事实上,你不能在类路径上同时有多个bindings(例如slf4j-simple.jarslf4j-logj12.jar)。在这里,您很可能会从另一个依赖项传递slf4j-simple.jar。要解决此问题,请运行 mvn dependency:tree 以找出它的来源,并在需要时将其排除。

顺便说一句,在您的情况下,我会将 Spring 配置为使用 SLF4J,因为 Hibernate 正在使用它。请按照第一段中提到的链接中的步骤进行操作。我会使用 logback 作为日志框架(它是 log4j 的继承者),这就是现在发生的事情。

【讨论】:

【参考方案3】:

您的类路径中需要一个 log4j.properties 文件。这是我昨天碰巧创建的一个最小属性文件:

log4j.logger.BillReview=INFO,BillReviewLog
log4j.appender.BillReviewLog=org.apache.log4j.RollingFileAppender
log4j.appender.BillReviewLog.File=BillReview.log
log4j.appender.BillReviewLog.Append=true
log4j.appender.BillReviewLog.MaxFileSize=5000KB
log4j.appender.BillReviewLog.MaxBackupIndex=5
log4j.appender.BillReviewLog.layout=org.apache.log4j.PatternLayout
log4j.appender.BillReviewLog.layout.ConversionPattern=%c %p %-10.10Xserver %-4.4Xuser %dISO8601 %m%n

将其放入 log4j.properties 文件中,将所有对“BillReview”的引用更改为更像您的项目的内容,这将记录到文件并停止这些消息。

您对哪个日志框架的问题主要是个人选择。 Log4j 是旧标准,它运行良好,Commons 日志记录和 slf4j 是较新的 API,允许一些更复杂的用例。

【讨论】:

【参考方案4】:

我会让一些比我回答第一个问题更有经验的大师。

回答你的第二个问题...

您可以使用 log4j.properties 或 log4j.xml 文件(哪个都没有关系)。无论您选择什么,都应该将它添加到类路径中(通常它应该与源代码位于同一目录中)。如果您使用 Spring,将 src 目录分解为逻辑部分的好方法是使用以下目录结构...

src/main/java -- 把主要源码放在这里 src/main/resources -- 把你主要来源使用的资源放在这里 src/test/java -- 将测试源放在这里(用于测试) src/test/resources -- 将测试资源放在这里

因此,您需要将 log4j.properties 放在 src/test/resources 目录中。

回答你的第三个子弹......

您可以通过执行以下操作在 pom.xml 文件中排除依赖项中的依赖项...

<dependency>
    <groupId>org.apache.xbean</groupId>
    <artifactId>xbean-spring</artifactId>
    <version>$xbean.version</version>
    <exclusions>
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

【讨论】:

【参考方案5】:

我在运行测试时在同一区域遇到了问题。我最终注意到,除了我想要的 slf4j-log4j12 之外,junit 还引入了 slf4j-nop 作为依赖项。一旦我排除了slf4j-nop,它就开始工作了。

【讨论】:

以上是关于对使用 Spring 和 Hibernate 的 Java 日志系统感到困惑的主要内容,如果未能解决你的问题,请参考以下文章

Spring框架学习spring整合hibernate

使用 Hibernate + Spring 进行缓存 - 一些问题

如何使用 Spring + Hibernate 对实体进行自定义验证以进行多租户设置

ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存

SSH框架的搭建和测试(Spring + Struts2 + Hibernate)

使用 spring 和 hibernate 测试数据库连接