如何让 ServletContextListener 停止 Java EE 应用程序?
我有一个 ServletContextListener,它在我的 Java EE 应用程序启动时执行一些数据库管理功能。它在 JPA 和应用程序的其他部分启动/加载之前在我的应用程序中运行。如果数据库维护失败,我会记录错误。如果数据库维护失败,应用程序将无法正常运行,我想停止该应用程序。
如何从 ServletContextListener.contextInitialized 优雅且正确地停止应用程序?
下面 Viven 给出的解决方案很接近,但并不完全。当我抛出 RuntimeException 时,Glassfish 处于不一致的状态,无法访问其管理控制台,但某些进程仍在运行并保持端口 3700(IIOP?)打开,从而阻止重新启动。
I have a ServletContextListener which performs some database management functions when my Java EE application starts. This runs in my application before JPA and other pieces of the application are started/loaded. If the database maintenance fails I am logging the errors. If the database maintenance fails the application will not function properly and I would like to halt the application.
How can I gracefully and correctly stop the application from ServletContextListener.contextInitialized?
Solution given by Viven below is close but not quite. When I throw a RuntimeException Glassfish is left in an inconsistent state where its admin console is not accessible but some process is still running and keeping port 3700 (IIOP?) open which then prevents a restart.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在侦听器中,捕获任何异常并使用 servlet 上下文属性来存储有关错误的标志或其他有用信息。您可能还应该记录一些内容来表明该应用程序无法运行。
此时,您的选择可能取决于应用程序的架构。如果所有请求都由单个控制器/调度程序 Servlet 处理,则让它的
init
方法检查上下文属性并抛出UnavailableException
可能是有意义的。请注意,该异常仅适用于引发该异常的特定 servlet。如果您的应用程序包含许多 servlet 或允许直接访问其他资源,这会使该方法更难以管理。另一种选择是创建一个过滤器来拦截每个请求,检查上下文属性,然后抛出异常。其他变化当然是可能的。
In your listener, catch any exceptions and use servlet context attributes to store flags or other useful information about the error. You should probably also log something to indicate that the app is non-functional.
At this point, your options may be dictated by the architecture of your app. If all requests are handled by a single controller/dispatcher servlet, it might make sense to have its
init
method check the context attributes and throw anUnavailableException
. Just be aware that the exception only applies to the specific servlet throwing it. This makes the approach less manageable if your app contains many servlets or allows direct access to other resources.Another option would be to create a filter that intercepts every request, checks the context attributes and then throws an exception. Other variations are certainly possible.
如果您的
ServletContextListener
引发异常,则 Web 应用程序将无法正确加载,并且应用程序服务器可能阻止所有后续请求(并以 500 错误响应)。它并不能完全阻止应用程序启动,也不能停止应用程序,但它可以阻止应用程序的任何进一步使用,并且可能对您的情况有用。
在规范中进行正确验证后,该行为在规范中不是强制性的。服务器可能(不是必须)返回 500 错误。因此,必须谨慎使用该解决方案。
请参阅此答案以获取 Servlet 规范的引用。
If your
ServletContextListener
throws an exception, the webapp won't load correctly and the application server may block all subsequent request (and respond with a 500 error).It isn't exactly preventing the application to start, nor stopping the application, but it prevents any further usage of the app and could be useful in your case.
After proper verification in the spec, this behaviour isn't mandatory in the specification. The server may (not must) return 500 errors. This solution has to be used carefully, therefore.
See this Answer for a quote from the Servlet spec.
以下是如何在不停止 Tomcat 本身的情况下正常停止 Tomcat 11* 上的 Web 应用程序:
*) 使用 Tomcat 11,因为它使用新的
jakarta.servlet
包命名。如果您希望使用 Tomcat 的早期版本,请将其更改为javax.servlet
。脚注:此答案基于:您可以使用 MBeans/JMX 关闭 Tomcat 中的单个应用程序
Here is how to gracefully stop the Web application on Tomcat 11* without stopping Tomcat itself:
*) Using Tomcat 11 because it uses the new
jakarta.servlet
package naming. If you wish to use a former version of Tomcat, change it tojavax.servlet
.Footnote: this answer is based on: You can shutdown a single application in Tomcat, using MBeans/JMX