我目前正在实施ServletContextListener
并使用contextDestroyed()
在关闭之前在我的网络应用程序上运行清理任务。但是,我一直在阅读Runtime.addShutdownHook(Thread)
如何用于同一目的。
在取消部署之前,这两种运行清理方法有什么区别吗?对于Web应用程序而言,哪个在功能,效率和可维护性方面更受欢迎?
答案 0 :(得分:8)
我认为ServletContextListener更适合Web应用程序,因为您为每个会话清理资源。
在关闭JVM的情况下执行关闭挂钩。那就是当你停止你的容器时,这是一次性事件。
答案 1 :(得分:4)
使用addShutdownHook()的危险在于,当您多次重新部署应用程序时,您可能会遇到类加载器泄漏。
因为关闭钩子的类(你的webapp中的一个Thread子类或一个Runnable实现)来自你的webapp的类加载器,即使在你的webapp被容器取消部署之后,关闭钩子仍将在系统中注册。这意味着整个webapp的类加载器不能被垃圾收集。
我肯定会推荐ServletContextListener。
答案 2 :(得分:3)
许多servlet容器支持动态删除和/或重新加载WAR的操作,而无需关闭JVM进程。因此,如果您将清理例程编写为ServletContextListener,则可能会在容器生命周期内多次运行。 (例如,如果在容器进程仍处于运行状态时多次修改并重新加载WAR。)
但是,如果使用Runtime.addShutdownHook实现清理,它将只运行一次:当整个容器的JVM关闭时。
ServletContextListener可能是您的正确答案,因为它将您的清理例程与Web应用程序的生命周期相结合,而不是托管它的容器进程的生命周期。
答案 3 :(得分:2)
我们正在谈论的泄漏只会在我们进行热/部署时发生。但是,如果在每次部署更改后重新启动服务器,则挂钩应该可以正常工作而不会发生内存泄 此外,另一个控制泄漏的因素是您试图通过侦听器/钩子控制的资源清理类型。
答案 4 :(得分:1)
为什么不两个都做?虽然ServletContextListener更适合于webapp,但我发现在开发期间,服务器经常突然停止,然后从不调用contextDestroyed(),因此您可以使用这两种机制来确保始终正常关闭:
实现ServletContextListener,其中contextInitialized调用addShutdownHook()和contextDestroyed调用removeShutdownHook()。 hook和contextDestroyed都可以委托一些内部方法来实际进行清理。
这样,如果正确调用了侦听器,那么钩子就会被添加和删除(但不会被调用)并且没有泄漏,但是如果服务器在没有上下文被破坏的情况下死掉,那么关闭钩子会清除它。