如何正确关闭 Spring 中的 ApplicationContext?

How correctly close the ApplicationContext in Spring?

我正在学习 Spring 核心认证,我对提供的研究中发现的这个问题有一些疑问 material:

What is the preferred way to close an application context?

我知道如果我有这样的东西:

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

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

但我认为这不是最好的方法。

看了官方文档我发现我也可以这样做:

context.registerShutdownHook();

向 JVM 注册一个关闭挂钩,因此 JVM 将在 JVM 退出前触发 Spring 的关闭阶段。因此在 JVM 退出时,Spring 的关闭阶段将执行。

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

所以我的问题是:

Tnx

On the documentation I can read that: usually not possible to call context.close() because many applications (web applications) run indefinitely But what exactly means this last assertion? why web application run indefinitely?

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

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

如您所知,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 方法(如果有的话)。

来自 :

The ApplicationContext class doesn't define either of these methods as a part of its interface, but the ConfigurableApplicationContext does define both of these.

来自 JavaDoc:

close() -- Close this application context, destroying all beans in its bean factory. registerShutdownHook() -- Register a shutdown hook with the JVM runtime, closing this context on JVM shutdown unless it has already been closed at that time. Basically, AbstractApplicationContext#close() will close, or shutdown, the ApplicationContext at the time it is invoked, while AbstractApplicationContext#registerShutdownHook() will close, or shutdown, the ApplicationContext at a later time when the JVM is shutting down for whatever reason. This will be achieved by utilizing the JVM shutdown hook functionality.

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

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