Java 你如何阻止春天吞咽异常?
当服务器端出现故障时,因为数据库和应用程序不同步,而不是出现错误,应用程序崩溃,spring/tomcat似乎吞下了异常并假装什么也没有发生 说我疯了,但如果程序灾难性地失败,我希望它真的灾难性地失败!是否有任何方法可以关闭这种行为?当服务器假装一切正常时,它只是在日志中抛出,这真的减慢了开发速度 如果这不是spring/tomcat的默认值,那么还有什么可能导致它呢? 不幸的是,我们正在使用大量的库和框架。斯普林通常是个嫌疑犯,但也可能是别的什么 更新 这是一个sql server数据库,我们正在使用Java 你如何阻止春天吞咽异常?,java,spring,tomcat,exception,Java,Spring,Tomcat,Exception,当服务器端出现故障时,因为数据库和应用程序不同步,而不是出现错误,应用程序崩溃,spring/tomcat似乎吞下了异常并假装什么也没有发生 说我疯了,但如果程序灾难性地失败,我希望它真的灾难性地失败!是否有任何方法可以关闭这种行为?当服务器假装一切正常时,它只是在日志中抛出,这真的减慢了开发速度 如果这不是spring/tomcat的默认值,那么还有什么可能导致它呢? 不幸的是,我们正在使用大量的库和框架。斯普林通常是个嫌疑犯,但也可能是别的什么 更新 这是一个sql server数据库,我们
SqlServerDataSource
连接该数据库。Hibernate在项目的某些部分中使用,但用于在登录时查询数据库。在客户端,我们使用extjs,还使用ExtDirectSpring为客户端的对话方法添加注释。要转换通过线路传输的数据,有Jackson,然后由extdirect json处理程序包装
有一些AOP的东西与记录异常有关,但是删除这些代码会导致相同的行为
进一步更新
好吧,让你的服务器崩溃不是个好主意!请参阅下面我的答案,了解我建议的中间立场。如果您确实想这样做(但我认为您不应该…),您可以使用一个过滤器,一旦应用程序释放未捕获的异常,它将阻止应用程序。可能是这样的:
public class CrashFilter implements Filter {
private boolean crashed = false;
private String msg = "Major problem : application stopped";
@Override
public void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc) throws IOException, ServletException {
if (crashed) {
HttpServletResponse resp = (HttpServletResponse) sr1;
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
return;
}
try {
fc.doFilter(sr, sr1);
}
catch (Exception ex) {
crashed = true;
throw new ServletException(ex);
}
}
// init and destroy omitted from brevity
}
好的,所以我最终做到了。我基本上使用了上面的想法,但认为有足够的额外内容来发布我自己的答案 事实证明,你真的不应该像其他人建议的那样做,我在底部加了一点说明原因 这是我的过滤器:
public class FailOnErrorFilter implements Filter
{
@Override
public void init(FilterConfig config) throws ServletException
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
{
try {
filterChain.doFilter(request, response);
}
catch (Exception exception) {
System.exit(1);
}
}
@Override
public void destroy()
{
}
}
要使其正常工作,您必须修改web.xml:
<filter>
<filter-name>failingFilter</filter-name>
<filter-class>fullyQualified.FailOnErrorFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>failingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
顾名思义,extdirectspring使用spring,因此它的依赖性对于调用代码来说并不明显,但是如果你去挖掘(它在github上)。您将在RouterController中看到它在catch中调用以下方法
private Object handleException(MethodInfo methodInfo, BaseResponse response, Exception e, HttpServletRequest request) {
return configurationService.getRouterExceptionHandler().handleException(methodInfo, response, e, request);
}
其中路由器控制器执行以下操作:
@Autowired(required = false)
private RouterExceptionHandler routerExceptionHandler;
public RouterExceptionHandler getRouterExceptionHandler() {
return routerExceptionHandler;
}
如果您不提供,它将设置默认值
更新-为什么不应该这样做
事实证明,您确实不应该在tomcat应用程序中调用System.exit
。它不仅会关闭应用程序,还会导致服务器退出。这也会导致其他正在运行的应用程序停止运行
由于其他一些原因,这也不合适:
- 如果一系列测试中的第一个抛出异常,那么所有后续测试都将失败
- 重新启动服务器非常耗时,您必须是破坏服务器的人才能看到异常
- 如果您在单独的机器上运行手动测试部署,那么如果某个地方出现问题,您必须重新启动服务器
- 在生产过程中,它会使每个人的应用程序停机,大多数用户无法重新启动服务器
- 在调试中,我们现在还将重定向到带有stacktrace的错误页面
- 在生产中,我们将直接重定向到“出错”页面。我们还将设置一个电子邮件服务,通知我们异常情况
- 对于UI/selenium测试,其工作原理与调试相同
- 对于headless Js测试,服务器拒绝后续请求,直到下一个测试重置服务器的错误状态
为了让事情变得更复杂,毫不奇怪,原来的webapp太脆弱,无法掩盖错误,因此我保留了旧的错误抑制功能,因为我们目前没有积极开发/修复它。你知道存在异常,还是只知道没有异常传播?如果是后者,则问题可能出现在数据库访问层(例如Hibernate或其他JPA提供程序)中,因为该层中定义的bean容忍并忽略额外的数据库列,并可能最终删除更新中的任何额外列。如果是前者,我只想说“不要使用Spring”,但这可能说起来容易做起来难。举一个灾难性失败的例子,它不会发出任何错误或警告。我非常怀疑Spring应该为此负责。什么样的数据库?给我们更多的上下文细节。你真的认为如果web应用程序释放了一个未捕获的异常,tomcat(因为Spring与此无关)应该崩溃吗???如果它真的这样做了,它将不会像实际那样被使用…@warrendew肯定会有例外。Hibernate正在项目的某些部分使用,但没有用于新的内容。感谢您的回复。上面例子中的resp是什么?它不能在我的机器上编译-我已经尝试了sr和sr1,但似乎都没有sendError方法。@JonnyLeeds:对不起,我忘了一行。。。后期编辑。您还应该在一行
((HttpServletResponse)sr1)中编写它代码>您知道您可以随时记录发生的致命错误。
并调用。。。但这样做的任何理由都是值得怀疑的(加上开发人员的理智)。只要检查Servlet规范,就有一种更好的标准方法来关闭web应用程序->抛出。
@Autowired(required = false)
private RouterExceptionHandler routerExceptionHandler;
public RouterExceptionHandler getRouterExceptionHandler() {
return routerExceptionHandler;
}