目前我们的应用程序正在升级到 Spring Boot 3,我们在运行时遇到了一些记录器工厂冲突的问题。
我们使用 logback 来实现日志记录,但通过 slf4j。
我们引入了
spring-boot-starter-logging
模块,并且没有在 build.gradle 中指定我们自己的 slf4j 或 logback 版本。
这是一个非常复杂的项目,有很多依赖项,但是日志记录依赖项都在这里:
integrationTestRuntimeClasspath - Runtime classpath of source set 'integration test'.
+--- net.logstash.logback:logstash-logback-encoder:6.6
| \--- com.fasterxml.jackson.core:jackson-databind:2.12.0 -> 2.14.2
| +--- com.fasterxml.jackson.core:jackson-annotations:2.14.2
| | \--- com.fasterxml.jackson:jackson-bom:2.14.2
| | +--- com.fasterxml.jackson.core:jackson-annotations:2.14.2 (c)
| | +--- com.fasterxml.jackson.core:jackson-core:2.14.2 (c)
| | +--- com.fasterxml.jackson.core:jackson-databind:2.14.2 (c)
| | +--- com.fasterxml.jackson.datatype:jackson-datatype-guava:2.14.2 (c)
| | +--- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.2 (c)
| | +--- com.fasterxml.jackson.module:jackson-module-parameter-names:2.14.2 (c)
| | +--- com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.14.2 (c)
| | +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2 (c)
| | \--- com.fasterxml.jackson.datatype:jackson-datatype-joda:2.14.2 (c)
| +--- com.fasterxml.jackson.core:jackson-core:2.14.2
| | \--- com.fasterxml.jackson:jackson-bom:2.14.2 (*)
| \--- com.fasterxml.jackson:jackson-bom:2.14.2 (*)
+--- org.springframework.boot:spring-boot-starter-logging -> 3.0.5
| \--- ch.qos.logback:logback-classic:1.4.6
| +--- ch.qos.logback:logback-core:1.4.6
| \--- org.slf4j:slf4j-api:2.0.4 -> 2.0.7
+--- org.springframework:spring-context -> 6.0.7
| +--- org.springframework:spring-aop:6.0.7
| | +--- org.springframework:spring-beans:6.0.7
| | | \--- org.springframework:spring-core:6.0.7
| | | \--- org.springframework:spring-jcl:6.0.7
| | \--- org.springframework:spring-core:6.0.7 (*)
| +--- org.springframework:spring-beans:6.0.7 (*)
| +--- org.springframework:spring-core:6.0.7 (*)
| \--- org.springframework:spring-expression:6.0.7
| \--- org.springframework:spring-core:6.0.7 (*)
+--- org.springframework:spring-beans -> 6.0.7 (*)
+--- com.fasterxml.jackson.core:jackson-databind:{strictly 2.14.2} -> 2.14.2 (*)
+--- com.fasterxml.jackson.core:jackson-annotations:{strictly 2.14.2} -> 2.14.2 (*)
+--- org.apache.tomcat.embed:tomcat-embed-core:9.0.69
| \--- org.apache.tomcat:tomcat-annotations-api:9.0.69 -> 10.1.7
+--- commons-logging:commons-logging:1.1.3 -> 1.2
我们将以下排除和依赖项应用于多模块构建中的所有模块:
configurations.all {
// Short version cache so we don't accidentally use old versions
resolutionStrategy.cacheDynamicVersionsFor 10, 'minutes'
exclude group: 'org.apache.logging.log4j', module: 'log4j-to-slf4j'
exclude group: 'org.apache.logging.log4j', module: 'log4j-api'
exclude group: 'org.slf4j', module: 'jul-to-slf4j'
exclude group: 'org.slf4j', module: 'slf4j-log4j'
exclude group: 'org.slf4j', module: 'slf4j-log4j12'
}
dependencies {
implementation 'net.logstash.logback:logstash-logback-encoder:6.6'
implementation 'org.springframework.boot:spring-boot-starter-logging'
运行我的集成测试给我:
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.helpers.SubstituteLoggerFactory loaded from file: .../.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/2.0.7/41eb7184ea9d556f23e18b5cb99cad1f8581fc00/slf4j-api-2.0.7.jar). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.helpers.SubstituteLoggerFactory
奇怪的是,这仅影响部分集成测试。其他都按预期运行。
我在这里有点不知所措。我不能排除 logback 或 slf4j,因为它们都是必需的。任何帮助将不胜感激。
编辑我今天早上做了一些调试,似乎正在发生的事情是,当
org.slf4j.LoggerFactory
正在初始化时,它返回替代记录器。
我们的问题已经到了底部。以下是所发生事情的摘要:
LoggerFactory
中,我们可以看到SLF4J正在寻找Logback作为提供者,并开始初始化它。logback.xml
并且显然初始化logstash
附加程序是一个相当慢的过程。问题的根本原因似乎是在 slf4j 初始化时,对
LoggerFactory#getProvider
方法的任何请求都会返回替代提供者,此时 Spring Boot 中的 LogbackLoggingSystem#getLoggerContext
会抛出异常,因为返回的 LoggerFactory
是无效。
我将针对 slf4j 的这种行为提出一个错误。我觉得如果它正在初始化,它不应该只返回一个虚拟实现。
Ben,您最终是否在 SLF4J 上产生了问题?我刚刚将我的项目更新到 Spring Boot 3.2.2(从 2.7.x)并遇到了同样的问题。我的具体错误是“LoggerFactory不是Logback LoggerContext,但Logback位于类路径上。删除Logback或竞争实现(从文件加载类org.slf4j.helpers.NOPLoggerFactory:/.m2/org/slf4j/slf4j-api/ 2.0.11/slf4j-api-2.0.11.jar)。如果您使用 WebLogic,则需要将“org.slf4j”添加到 WEB-INF/weblogic.xml 中的首选应用程序包中:org.slf4j.helpers .NOPLoggerFactory”
我们使用的是 spring-boot-starter-logging 标准的 logback,而不是使用 Log4j。我们也仅使用文件和控制台附加程序,因此初始化不会像您的情况那样花费很长时间。知道这是怎么回事吗?