7

我目前正在实施ServletContextListener并使用contextDestroyed()它在我的 Web 应用程序关闭之前运行它的清理任务。但是,我一直在阅读有关如何Runtime.addShutdownHook(Thread)将其用于相同目的的信息。

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

4

5 回答 5

8

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

在 JVM 关闭的情况下执行关闭挂钩。那将是您停止容器时,这是一次性事件。

于 2011-08-05T01:18:53.370 回答
5

使用 addShutdownHook() 的危险在于,您可能会遇到类加载器泄漏,当您多次重新部署应用程序时,这种泄漏会变得很明显。

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

我肯定会推荐 ServletContextListener。

于 2011-08-05T01:54:56.813 回答
4

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

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

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

于 2011-08-05T01:27:47.657 回答
2

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

于 2011-10-31T03:38:28.157 回答
2

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

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

这样,如果正确调用了侦听器,则添加和删除钩子(但未调用)并且没有泄漏,但是如果服务器在没有销毁上下文的情况下死亡,则关闭钩子会清理干净。

于 2017-02-22T21:55:30.413 回答