【问题标题】:How correctly close the ApplicationContext in Spring?在 Spring 中如何正确关闭 ApplicationContext?
【发布时间】:2015-05-24 01:29:39
【问题描述】:

我正在学习 Spring Core 认证,我对在提供的学习材料中发现的这个问题有些疑问:

关闭应用程序上下文的首选方式是什么?

我知道如果我有这样的事情:

ConfigurableApplicationContext context = …
// Destroy the application
context.close();

通过在 context 对象上使用 close() 方法,ApplicationContext 被关闭并且应用程序被销毁。

但我认为这不是我必须这样做的最佳方式。

阅读官方文档我发现我也可以这样做:

context.registerShutdownHook();

向 JVM 注册一个 Shutdown Hook,因此 JVM 将在 JVM 退出之前触发 Spring 的关闭阶段。所以在 JVM 退出时,Spring 的关闭阶段将执行。

在文档中我可以读到:通常不可能调用context.close(),因为许多应用程序(Web 应用程序)无限期地运行 但是最后一个断言到底意味着什么?为什么 Web 应用程序会无限期运行?

所以我的问题是:

  • 我可以使用第二种方法关闭应用程序上下文,也可以使用非 Web 应用程序吗?
  • 是否优先尊重context.close()

Tnx

【问题讨论】:

  • many applications (web applications) run indefinitely..它通常指的是在无限循环中发生的事情,除非你停止这个过程,比如你的 SocketServer 监听传入的请求。为什么要首先手动关闭 WebApplicationContext ?它通常在服务器启动时创建并在服务器关闭时销毁
  • Web 应用程序永远不会停止,因为如果您这样做,站点就会关闭。如果您想停止运行 Web 应用程序,您将关闭它(例如通过停止 Web 服务器)。当您这样做时,JVM 也将停止,因此“关闭 JVM 挂钩”是关闭 JVM 上下文的方法。为什么要停止上下文?
  • close 用于 Web 应用程序,而 shutDownHook 用于独立应用程序。刚刚发布了我的答案,并提供了更多细节:)

标签: java spring spring-mvc applicationcontext


【解决方案1】:

如您所知,ContextLoaderListener 负责初始化和销毁​​您的 ApplicationContext,当您关闭服务器时,将调用 ContextLoaderListener 的 contextDestroyed 方法。

  public void contextDestroyed(ServletContextEvent event){
    closeWebApplicationContext(event.getServletContext());
    ContextCleanupListener.cleanupAttributes(event.getServletContext());
  }

在那个closeWebApplicationContext中,他们实际上像这样在ApplicationContext上调用close方法

  if ((this.context instanceof ConfigurableWebApplicationContext)) {
    ((ConfigurableWebApplicationContext)this.context).close();
  }

这是直接来自spring-web-4.1.5.jar。从这里可以看出,他们使用close 来销毁Web 应用程序中的ApplicationContext。

registerShutdownHook 用于显式关闭非 Web 应用程序中的 IoC 容器,例如独立桌面应用程序,特别是当您从 ClassPathXmlApplicationContext(或)FileSystemXmlApplicationContext(或)其他类型手动创建 ApplicationContext 时。

这样做是为了释放你的 spring 应用程序使用的所有资源,并在你的 spring bean 上调用 destroy 方法(如果有)。

【讨论】:

  • 在独立应用程序中,例如后台服务或者桌面应用,当你进入main方法,你做应用上下文,现在我的问题是,如果你注册了JVM Hook,你退出了main方法,这会破坏上下文吗?
【解决方案2】:

在文档中我可以读到:通常不可能调用 context.close() 因为许多应用程序(Web 应用程序)无限期地运行 但是最后一个断言到底意味着什么?为什么 Web 应用程序会无限期运行?

只要部署它的应用程序服务器运行,Web 应用程序就会运行。正确启动和停止应用程序取决于应用程序服务器(而不是您)。这意味着当应用程序服务器停止时,servlet 上下文将被销毁。在 Spring 应用程序中,web.xml 中注册的 ContextLoaderListener 类会监听此事件(上下文已销毁)以正确关闭 Spring 上下文。

在应用程序服务器之外使用 Spring(如独立应用程序)时,由您决定是否正确停止 Spring 上下文。正如您所说,这可以通过显式调用 context.close() 或注册一个为您进行此调用的关闭挂钩 (context.registerShutdownHook()) 来完成。

【讨论】:

  • 好的,但是 context.registerShutdownHook() 比 context.close() 更好吗?
  • registerShutdownHook()close() 方法调用相同的代码来关闭 Spring 上下文。你可以在AbstractApplicationContext看到。
【解决方案3】:

来自https://stackoverflow.com/a/42018369

ApplicationContext 类没有将这些方法中的任何一个定义为其接口的一部分,但 ConfigurableApplicationContext 确实定义了这两个。

来自 JavaDoc:

close() -- 关闭此应用程序上下文,销毁其 bean 工厂中的所有 bean。 registerShutdownHook() -- 向 JVM 运行时注册一个关闭钩子,在 JVM 关闭时关闭此上下文,除非它当时已经关闭。 基本上,AbstractApplicationContext#close() 将在调用 ApplicationContext 时关闭或关闭它,而AbstractApplicationContext#registerShutdownHook() 将在稍后 JVM 因任何原因关闭时关闭或关闭 ApplicationContext。这将通过利用 JVM 关闭挂钩功能来实现。

在任何一种情况下,实际的关闭都是由doClose() 方法完成的。

如果您对为什么您的输出看起来如此相似感到好奇,那是因为它们实际上在做同样的事情,无论您在示例的第 3 行调用 close() 还是 registerShutdownHook()close() 将立即关闭,registerShutdownHook() 将在 JVM 退出之前关闭,这几乎是在方法调用完成后立即关闭,因为它是最后一行代码!

【讨论】:

    猜你喜欢
    • 2013-01-03
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多