如何在ServletContextListener中遇到异常时终止Tomcat启动?

11

我有一个实现了 ServletContextListener 接口的类,在启动时加载了一些资源。

这些资源对应用程序非常重要,如果我的逻辑中发生了某些糟糕的事件,我希望整个启动过程都失败。

ServletContextListener.contextInitialized() 方法内部,是否有任何命令可以执行来停止并使整个Tomcat启动失败?


除了 System.exit(1) 之外,有人找到其他的方法了吗? - Bastien
@Bastien,请使用SpringBoot。 - L. Holanda
4
@Leo 不相关。对于这个问题的正确回答应该是解释SpringBoot如何处理这个问题。 - Bastien
@Leo,我已经尝试了你提供的方法,但这只是一个解决办法,并没有解决问题的本质。 - Bastien
我不认为这是一个变通方法。在我看来,使用System.exit()才是唯一的解决方案。毕竟,除非你正在编写唯一部署的应用程序,否则不应该中止Tomcat启动。然而,确保每个Tomcat仅有一个应用程序的最佳方法是使用内嵌式一个。我认为这是正确的做法。请看这篇文章:http://www.beyondjava.net/blog/application-servers-sort-of-dead/ - L. Holanda
显示剩余3条评论
2个回答

12

尝试指定:

-Dorg.apache.catalina.startup.EXIT_ON_INIT_FAILURE=true

在您的java运行时选项中,引用官方文档

如果为true,则服务器在服务器初始化阶段发生异常时将退出。

如果未指定,则将使用默认值false。

更新:

如果您想通过代码实现此功能,System.exit()是否有效?

public class FailFastListener implements ServletContextListener {
    
    private static final Logger log = LoggerFactory.getLogger(FailFastListener.class);
    
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        try {
            //initialization
        } catch(Exception e) {
            log.error("Sooo bad, shutting down", e);
            System.exit(1);
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
    }
}

你可以使用 模式来包装现有的监听器,而不会使它们混乱不堪。虽然不确定 Tomcat 会如何反应...

谢谢,那几乎解决了我的问题,但是...我想通过代码执行来实现它。如果不可能的话 - 我将使用运行时选项。 - urir
是的 :) 神奇的 System.exit(1) :) 我知道,我应该更清晰地表达我的问题... 那么... 有没有通过检索 Tomcat 容器来实现它的方法?主要原因是我担心 System.exit 不会关闭生命周期中的其他事件,比如其他监听器的“销毁”代码... 你对此有什么看法? - urir
1
当启用安全管理器时,System.exit()将无法工作。 - Stefan
4
有人找到除了System.exit(1)之外的其他方法吗?在这种情况下,-Dorg.apache.catalina.startup.EXIT_ON_INIT_FAILURE=true不起作用,因为contextInitialized方法中的异常不被视为服务器故障,而只是Servlet故障。 - Bastien
不要使用System.exit。在CWE知识库中,它被列为不良实践:CWE-382:J2EE不良实践:使用System.exit() http://cwe.mitre.org/data/definitions/382.html - L. Holanda
@L.Holanda 从Servlet的doPost/doGet方法中调用它是不好的实践。但是从ServletContextListener中调用它是完全可以的。 - turbanoff

2
如果您想停止Tomcat,因为您的Web应用程序无法部署,我假设您没有其他应用程序部署到Tomcat。在这种情况下,为什么不将此应用程序构建为带有嵌入式Tomcat / Jetty的独立Web应用程序?这样,只要您的Web应用程序无法正确启动,嵌入式服务器也将关闭。
对我来说,您似乎专注于使用ServletContextListener解决并非ServletContextListener的问题。
不要使用System.exit(),因为它会终止可能正在运行其他已部署应用程序的服务器。如果可以接受,因为您知道永远不会有其他应用程序(并且您不想要其他应用程序),那么请制作一个独立的Web应用程序。这种不良实践在CWE中被列为潜在弱点:CWE-382 只是一个提示:Spring Boot通过嵌入式服务器简化了构建独立Web应用程序的工作。请参阅此指南:https://spring.io/guides/gs/spring-boot/ 很好的文章,解释了为什么这可能是你要找的东西:http://www.beyondjava.net/blog/application-servers-sort-of-dead/

1
我点赞你是因为你一般来说是正确的,然而Tomcat是一种特殊情况,因为嵌入式的tomcat并不总是真正的嵌入式……也就是说仍然使用多个类加载器。例如,Tomcat Maven插件会将一个单独的WAR转换成可执行的JAR,但实际上它运行起来非常类似于普通的Tomcat。Spring Boot不会这样做,因为它是父级,Tomcat在同一个类加载器中运行。实际上有多个类加载器(即tomcat maven插件的方式)是有好处的,因为你可以避免与Tomcat的jar包(例如其在日志记录方面的选择)相关的问题。 - Adam Gent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接