log4j2无法注册关闭挂钩,因为JVM正在关闭

Gra*_*ant 5 java logging log4j apache-commons log4j2

我正在尝试在基于tomcat的Web应用程序中使用log4j2,所以我添加了log4j web模块以及其他必需的jar.但是,当停止此Web应用程序时,我得到以下异常.

FATAL Unable to register shutdown hook because JVM is shutting down
Run Code Online (Sandbox Code Playgroud)

为什么我收到此错误以及我可以采取哪些措施来防止此错误?

谢谢!

ocr*_*mot 9

正如Pouriya的回答中所解释的那样,当你的应用程序在没有正确的关闭挂钩的情况下停止时,你可能正在尝试使用Log4j2.由于您在谈论Tomcat Web应用程序,我假设您正在使用Servlet.(如果没有,请参阅下面的第二部分).然后,您必须在ContextListener中声明:

public class ContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent evt) {
        String appenderName = evt.getServletContext().getInitParameter("log4jContextName");
        File file = new File(evt.getServletContext().getInitParameter("log4jConfiguration"));
        if(!file.exists()){
            logger = LogManager.getRootLogger();
        } else{
            logger = LogManager.getLogger(appenderName);
        }
    }
}

@Override
public void contextDestroyed(ServletContextEvent evt) {
    // You don't really need to do anything here, about the logger.
    // The log4j2 JAR will handle it properly.
}
Run Code Online (Sandbox Code Playgroud)

与Web应用程序一样,Log4J2的配置文件必须在web.xml文件中指示,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<web-app ... >
    <context-param>
        <param-name>log4jContextName</param-name>
        <param-value>myApplication</param-value>
    </context-param>

    <context-param>
        <param-name>log4jConfiguration</param-name>
        <param-value>/the/path/to/your/log4j.properties.file</param-value>
    </context-param>
</web-app>
Run Code Online (Sandbox Code Playgroud)

如果您使用的是普通应用程序,那么您需要明确添加关闭钩子:

public static void main( String[] args ) {

    ...

    File file = new File(logFileName);
    if(!file.exists()){
        logger = LogManager.getRootLogger();
    } else {
        System.setProperty("log4j.configurationFile", file.toURI().toURL().toString());
        logger = LogManager.getLogger("yourProgramName");
    }

    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            logger.info("Shutting down - closing application");
            // Shut down everything (e.g. threads) that you need to.

            // then shut down log4j
            if( LogManager.getContext() instanceof LoggerContext ) {
                logger.debug("Shutting down log4j2");
                Configurator.shutdown((LoggerContext)LogManager.getContext());
            } else
                logger.warn("Unable to shutdown log4j2");

            // logger not usable anymore
            System.out.println("Done.");
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

应用程序结束时(即调用时)将调用关闭挂钩System.exit(0).

您还需要在Log4J2配置文件中添加它:

XML版本:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration shutdownHook="disable">
...
</Configuration>
Run Code Online (Sandbox Code Playgroud)

Json版本:

{"configuration":
    {
        "shutdownHook":"disable",
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

这将告诉Log4j2您正在自己处理Logger的关闭.

(因为在普通应用程序中,您没有web.xml文件,所以必须以其他方式检索配置文件).


Pou*_*ian 4

如果您在停止 Web 应用程序时收到该错误,则意味着您的挂钩尚未在正确的时间注册。根据定义,它应该之前已经注册,以便在关闭期间实际上可以调用它。