你如何阻止春季吞咽异常?

时间:2014-06-27 16:42:23

标签: java spring tomcat exception

当服务器端出现故障时,因为数据库和应用程序不同步而不是出错并且应用程序崩溃spring / tomcat似乎吞下了异常并假装没有发生任何事情。

叫我疯了,但如果程序灾难性地失败,我希望它实际上是灾难性的失败!反正有关闭此行为?当服务器假装一切都很好时,当它刚刚被扔进日志中时,它真的会减慢开发速度。

如果这不是spring / tomcat的默认值,那么还有什么可能导致它? 不幸的是,我们正在使用大量的库和框架。春天将是通常的嫌疑人,但它可能是别的。

更新

它是我们使用SqlServerDataSource连接的SQL Server数据库。 Hibernate在项目的某些部分使用,但用于在登录时查询数据库。在客户端,我们使用extjs,我们也使用ExtDirectSpring来注释客户端进行通信的方法。为了翻译线路上的数据,杰克逊将被extdirect json处理程序包裹起来。

有一些AOP的东西与记录异常有关,但删除该代码会导致相同的行为。

进一步更新

好吧让你的服务器崩溃不是一个好主意!请参阅下面的答案,了解我提出的中间立场。

2 个答案:

答案 0 :(得分:1)

如果你真的想这样做(但恕我直言,你不应该...)你可以使用一个过滤器,一旦它让一个未捕获的异常消失,它就会阻止它。它可能是这样的:

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
}

答案 1 :(得分:1)

好的,我最后这样做了。我基本上已经使用了上面的想法,但认为有足够的额外发表我自己的答案。

事实证明你真的不应该像其他人建议的那样这样做,我在底部添加了一点来说出原因!

这是我的过滤器:

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

完成上述操作后,我意识到ExtDirectSpring是另一个罪魁祸首。它的默认行为是吞下服务器端方法中的所有异常。

我担心我将不得不修补图书馆,但幸好其他人已经抱怨过这个问题并在1.3.6中修复了。最初我尝试升级到最新版本但它破坏了大量代码!多么棒的图书馆。无论如何1.3.6增加了通过执行以下操作来关闭错误抑制的能力:

//this is to switch off blanket switching of exceptions in extdirect spring
@Component
public class NoExceptionHandling implements RouterExceptionHandler
{
    @Override
    public Object handleException(MethodInfo methodInfo, BaseResponse baseResponse, Exception e, HttpServletRequest httpServletRequest)
    {
        throw new RuntimeException(e);
    }
}

顾名思义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。它不仅会降低您的应用程序,还会导致服务器退出。这会导致任何其他运行应用程序停止运行!

由于其他一些原因,它也不合适:

  • 如果一系列测试中的第一个抛出异常,那么所有后续测试都将失败
  • 重启服务器非常耗时,您必须成为打破它才能看到异常的人
  • 如果您在单独的计算机上运行手动测试部署,那么如果某些地方出现问题,您必须重新启动服务器。

同样地:

  • 在制作过程中,每个人的应用程序都会关闭,大多数用户都无法重启服务器。

我在做什么

错误已经写入了tomcat日志+数据库。

  • 在调试中,我们现在也将使用stacktrace
  • 重定向到错误页面
  • 在制作中,我们只是重定向到“出错了”页面。我们还将设置一个电子邮件服务,通知我们例外情况。
  • 对于UI / selenium测试 - 它的工作方式与debug
  • 相同
  • 对于无头Js测试,服务器拒绝后续请求,直到下一次测试重置服务器的错误状态

只是为了让事情变得更复杂,不出所料,原始的webapp太脆弱,不能掩盖错误,所以我保留了旧的错误抑制,因为我们目前还没有积极开发/修复它。