我正在使用 Spring,并且在终止时我让 @PreDestroy 清理 bean。我不明白为什么日志记录有时会成功,而有时会失败。
// Using Log4j2
Logger log = LogManager.getLogger(MyClass.class);
@PreDestroy
public void close() {
log.warn("Test");
}
有时我什么也得不到(没有记录“测试”),其他时候我会得到:
[13:48:44] INFO MyClass: Test
如果我包括System.out.println("Is this run?");
在 close() 方法中,它总是会打印。
我实际上不确定发生了什么。我不知道是否是因为 JVM 正在关闭并且记录器被杀死......但我认为这会引发某种异常?
请注意,日志记录都记录到文件+标准输出,我不知道这是否会影响任何内容。日志记录对于其他无数行代码都可以正常工作,但对于这行代码却不行。
注意:如果最终成为这个特定的库,我愿意切换日志库。
编辑:MyClass 将是 spring.xml 文档中的一个 bean。
我认为归根结底是这样的,从Runtime.addShutdownHook https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook-java.lang.Thread-:
当虚拟机开始其关闭序列时,它将启动所有已注册的关闭挂钩一些未指定的订单并让它们同时运行。
因此,只要 LogManager 和 Spring IOC 容器都被 JVM 关闭钩子关闭,就无法确保消息会被记录下来。如果LogManager先关闭,消息就会丢失。如果首先关闭 IOC 容器,则会记录该消息。
如果您在 JEE 容器中运行,您可能几乎无法改变这一点。
但是,如果您在独立环境中运行,则可以添加shutdownHook="disable"
到 Log4j 2<configuration>
标签。这会阻止 Log4j 2 注册它自己的关闭挂钩。然后,而不是调用ctx.registerShutdownHook()
(关闭 IOC 的推荐方法),您注册自己的关闭挂钩。就像是:
class MyShutdownHook extends Thread {
private AbstractApplicationContext ctx;
public MyShutdownHook(AbstractApplicationContext ctx) {
this.ctx = ctx;
}
public void run() {
ctx.close();
Set<LoggerContext> contexts = new HashSet<>();
for (Logger logger : LoggerContext.getLoggers()) {
contexts.add(logger.getContext());
}
for (LoggerContext ctx : contexts) {
Configurator.shutdown(LogManager.getContext());
}
}
}
AbstractApplicationContext ctx = /* create context */
Runtime.getRunTime().addShutdownHook(new MyShutdownHook(ctx);
更新:更正了关闭 Log4j2 的过程。
警告:我远离我常用的构建机器,所以我没有编译这个,但我相信它使用了正确的 API。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)