Spring Boot应用上下文关闭后无日志输出,是否为框架Bug?
上下文关闭后JUL日志无输出,是否属于Spring Boot Bug?
测试代码
以下是用于验证日志输出的Spring Boot程序:
package test; import java.lang.System.Logger; import java.lang.System.Logger.Level; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Test { private static final Logger LOGGER = System.getLogger(Test.class.getName()); public static void main(String[] args) { LOGGER.log(Level.INFO, "Before loading Spring Boot"); try (var context = SpringApplication.run(Test.class)) { LOGGER.log(Level.INFO, "While Spring Boot is running"); } LOGGER.log(Level.INFO, "After application context has been closed"); } }
输出日志
运行程序后生成的日志如下:
mar 05, 2023 6:56:10 AM test.Test main INFO: Before loading Spring Boot . ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.0.3) 2023-03-05T06:56:10.582+01:00 INFO 15944 --- [ main] test.Test : Starting Test using Java 17.0.2 with PID 15944 (C:\dev\git\tsv-product\tsv-java\tsv-bom\tsv-lib\tsv-kernel-bom\tsv-kernel-lib\tsv_test\target\classes started by Mirko in C:\dev\git\tsv-product\tsv-java\tsv-bom\tsv-lib\tsv-kernel-bom\tsv-kernel-lib\tsv_test) 2023-03-05T06:56:10.585+01:00 INFO 15944 --- [ main] test.Test : No active profile set, falling back to 1 default profile: "default" 2023-03-05T06:56:11.107+01:00 INFO 15944 --- [ main] test.Test : Started Test in 0.854 seconds (process running for 1.14) 2023-03-05T06:56:11.112+01:00 INFO 15944 --- [ main] test.Test : While Spring Boot is running
预期与实际对比
- 符合预期:Spring Boot加载前,调用了JDK默认日志(JUL)。
- 符合预期:应用上下文运行时,调用了Spring Boot默认日志(Logback)。
- 不符合预期:应用上下文关闭后,无任何日志输出,预期至少会调用JUL。
Maven配置
使用的极简Maven配置如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>test</groupId> <artifactId>test</artifactId> <version>0.0.1-SNAPSHOT</version> <name>test</name> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.10.1</version> <configuration> <release>17</release> </configuration> </plugin> </plugins> </build> </project>
结论与解释
这不是Spring Boot的Bug,核心原因是日志系统的桥接与关闭逻辑:
- Spring Boot默认使用Logback作为日志框架,启动时会通过
LoggingApplicationListener将JUL(java.util.logging)的日志管理器替换为适配SLF4J/Logback的桥接实现,目的是让JUL日志也能通过Logback统一输出。 - 当try-with-resources块结束,应用上下文关闭时,Spring会触发日志系统的关闭流程:Logback的上下文被停止,同时JUL的桥接日志管理器被清理,但JDK原生的LogManager不会被自动恢复。
- 此时调用
System.getLogger()输出日志时,JUL已经没有有效的日志处理器,导致日志无法输出。
解决办法
- 优先使用SLF4J API(如
org.slf4j.Logger)替代JUL,即使应用上下文关闭后,只要手动重新初始化Logback,就能继续输出日志。 - 若必须使用JUL,可以在应用关闭前手动恢复JDK原生的LogManager,示例代码如下:
// 在try块结束前添加 java.util.logging.LogManager.getLogManager().reset(); // 重新添加JUL的控制台处理器 java.util.logging.ConsoleHandler handler = new java.util.logging.ConsoleHandler(); handler.setLevel(java.util.logging.Level.INFO); java.util.logging.LogManager.getLogManager().getLogger("").addHandler(handler);
内容的提问来源于stack exchange,提问作者Mirko Scotti
相关产品推荐
相关产品推荐

