且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Spring的@PreDestroy导致记录随机而不是日志记录

更新时间:2023-01-27 12:44:58

我认为归结为此,来自 Runtime.addShutdownHook

I think it comes down to this, from Runtime.addShutdownHook:


当虚拟机开始关机时,它将启动所有已注册的关闭钩子都在 某些未指定的顺序 中并让它们同时运行。

When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently.

因此,只要LogManager和Spring IOC容器都被JVM关闭挂钩关闭,就无法确保将记录消息。如果首先关闭LogManager,则消息将丢失。如果首先关闭IOC容器,则会记录该消息。

So, as long as LogManager and the Spring IOC container are both shut down by JVM shutdown hooks, there is no way to ensure the message will be recorded. If the LogManager is shut down first, the message is lost. If the IOC container is shut down first, the message is recorded.

如果您在JEE容器中运行,则可能无法更改此消息。

If you are running in a JEE container, there's probably little you can do to change this.

但是,如果您在独立环境中运行,可以添加 shutdownHook =disable到Log4j 2 < configuration> 标记。这可以防止Log4j 2注册它自己的关闭钩子。然后,不是调用 ctx.registerShutdownHook()(关闭IOC的推荐方法),而是注册自己的关闭钩子。类似于:

However, if you're running in a stand-alone environment, you can add a shutdownHook="disable" to the Log4j 2 <configuration> tag. This prevents Log4j 2 from registering it's own shutdown hook. Then, instead of calling ctx.registerShutdownHook() (the recommended way to shutdown the IOC), you register your own shutdown hook. Something like:

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。

Update: Corrected process of shutting down Log4j2.
Caveat: I am away from my usual build machines, so I have not compiled this, but I believe it's hitting the correct APIs.