Java contextDestroyed()与addShutdownHook()的比较

Java contextDestroyed()与addShutdownHook()的比较,java,application-shutdown,servlet-listeners,Java,Application Shutdown,Servlet Listeners,我目前正在实现ServletContextListener,并使用它在web应用程序关闭前运行清理任务。然而,我一直在读关于如何将其用于相同的目的 在取消部署之前运行清理的这两种方法之间有什么区别吗?就功能、效率和可维护性而言,哪一个更适合web应用程序?我认为ServletContextListener更适合web应用程序,因为您需要为每个会话清理资源 当JVM关闭时,执行关闭钩子。这将是当您停止容器时,这是一个一次性事件 许多servlet容器支持在不关闭JVM进程的情况下动态删除和/或重新

我目前正在实现
ServletContextListener
,并使用它在web应用程序关闭前运行清理任务。然而,我一直在读关于如何将其用于相同的目的


在取消部署之前运行清理的这两种方法之间有什么区别吗?就功能、效率和可维护性而言,哪一个更适合web应用程序?

我认为ServletContextListener更适合web应用程序,因为您需要为每个会话清理资源


当JVM关闭时,执行关闭钩子。这将是当您停止容器时,这是一个一次性事件

许多servlet容器支持在不关闭JVM进程的情况下动态删除和/或重新加载WAR的操作。因此,如果您以ServletContextListener的形式编写清理例程,它可能会在容器的生命周期内运行多次。(例如,如果在容器进程仍处于运行状态时多次修改和重新加载WAR。)

但是,如果您使用Runtime.addShutdownHook实现清理,它将只运行一次:当容器的JVM作为一个整体关闭时


ServletContextListener可能是您的正确答案,因为它将清理例程与web应用程序的生命周期相结合,而不是与承载它的容器进程的生命周期相结合。

使用addShutdownHook()的危险你可能会得到一个类加载器漏洞,当你多次重新部署你的应用程序时,这个漏洞会变得很明显

因为关闭钩子的类(线程子类或webapp中的可运行实现)来自webapp的类加载器,即使容器取消部署webapp,关闭钩子仍将在系统中注册。这意味着不能对整个webapp的类加载器进行垃圾收集


我绝对推荐ServletContextListener。

我们正在讨论的泄漏只有在进行热/部署时才会发生。然而,若在每次部署更改后重新启动服务器,那个么钩子应该可以正常工作,而不会出现内存泄漏。
另外,控制泄漏的另一个因素是您试图通过侦听器/钩子控制的资源清理类型。

为什么不同时执行这两种操作?虽然ServletContextListener更适合于webapp,但我发现在开发过程中,服务器通常会突然停止,然后从不调用contextDestroyed(),因此您可以同时使用这两种机制来确保始终正常关闭:

实现一个ServletContextListener,其中contextInitialized调用addShutdownHook(),contextDestroyed调用removeShutdownHook()。钩子和contextDestroyed都可以委托给某个内部方法来实际执行清理


这样,如果侦听器被正确调用,那么钩子就会被添加和删除(但不会被调用),并且不会出现泄漏,但是如果服务器在没有破坏上下文的情况下死亡,那么关闭钩子会清理掉所有内容。

这是对先前答案的注释,而不是答案本身。