0

我有一个 JSF 应用程序,我想确保在它出现 HTTP 500 错误时为用户提供有意义的响应。当我强制执行 OutOfMemoryError 时,该应用程序会死掉,但我从 Tomcat 6.0.35 得到一个默认的 500 错误页面。

我的应用程序设置的相关部分是:

网页.xml:

<filter>
    <filter-name>Error</filter-name>
    <filter-class>myApp.ErrorFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>Error</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

...

<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/expiredIndex.jsf</location>
</error-page>
<error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/error.jsf</location>
</error-page>

错误过滤器.java:

public class ErrorFilter implements Filter {

static Logger logger = Logger.getLogger("MYAPP");

@Override
public void destroy() {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    try {
        chain.doFilter(request, response);
    } catch (ServletException e) {
        logger.error(getDirID()+"|"+"Caught Servlet Exception");
        Throwable rootCause = e.getRootCause();
        logger.error(getDirID()+"|"+"Root cause is " + rootCause.toString());

        if (rootCause instanceof RuntimeException) { // This is true for any FacesException.
            logger.error(getDirID()+"|"+"Rethrowing exception as RuntimeException" + rootCause.toString());
            throw (RuntimeException) rootCause; // Throw wrapped RuntimeException instead of ServletException.
        } else {
            throw e;
        }
    }
}

@Override
public void init(FilterConfig arg0) throws ServletException {
}

public String getDirID() {
    DirID newDirID = new DirID();
    String dirID = newDirID.getDirID();

    return dirID;
}

}

减少堆栈跟踪为您的乐趣:

2012-09-17 17:35:51,881|ERROR|[http-8080-1]:Exception in the filter chain
javax.servlet.ServletException: Servlet execution threw an exception
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:313)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

...

Caused by: java.lang.OutOfMemoryError: Java heap space
at com.sun.facelets.util.FastWriter.overflow(FastWriter.java:50)
at com.sun.facelets.util.FastWriter.write(FastWriter.java:57)

...

 Sep 17, 2012 5:35:51 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
    at myApp.DirID.getDirID(DirID.java:27)
    at myApp.ErrorFilter.getDirID(ErrorFilter.java:50)
    at myApp.ErrorFilter.doFilter(ErrorFilter.java:31)

可能是最相关的位:

Sep 17, 2012 5:35:51 PM com.sun.faces.lifecycle.Phase doPhase
SEVERE: JSF1054: (Phase ID: RESTORE_VIEW 1, View ID: ) Exception thrown during phase execution: javax.faces.event.PhaseEvent[source=com.sun.faces.lifecycle.LifecycleImpl@16968dd]
Sep 17, 2012 5:35:51 PM org.apache.catalina.core.ApplicationDispatcher invoke
SEVERE: Servlet.service() for servlet Faces Servlet threw exception
javax.faces.application.ViewExpiredException: viewId:/error.jsf - View /error.jsf could not be restored.

现在我对此的看法是,容器在达到最大内存限制时会死掉,因此在堆栈所在的状态下无法访问 error.jsf posh 错误页面。

我的问题是:

  1. 鉴于原因是突然的内存不足错误,我可以从中恢复,以便服务器有足够的空间重定向到我的 error.jsf 页面吗?
  2. 如果对 1 的回答是肯定的,那么最有效的实现方法是什么(最好使用代码片段来获得最大的权威性)。

谢谢

4

2 回答 2

1

基本上,1 的答案是否定的,你不应该尝试从 OOM 错误中恢复(更多信息在这里,并检查评论和答案中提供的链接)。该错误将发布在您的 tomcat 日志和您的 Web 应用程序日志(如果有)中。

如果您遇到 OOM,我会使用像VisualVM这样的 Profiler来检查问题可能出在哪里并尝试解决问题。

附加信息:


另一件事,您可以使用错误代码处理错误,只需将其添加到您的 web.xml 中:

<error-page>
    <error-code>500</error-code>
    <location>/ErrorForCode500.html</location>
</error-page>
于 2012-09-17T23:05:10.413 回答
1

Once you hit an OOM exception, the entire state of the application is suspect and shouldn't be recovered. Trying to handle it is kind of noble, but it's far more important to make sure it doesn't happen.

于 2012-09-17T23:09:12.390 回答