java 捕获所有 Tomcat (GWT) servlet 中所有未处理异常的最佳方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14054146/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to catch all unhandled exceptions in all Tomcat (GWT) servlets
提问by Hollerweger
I use Tomcat 7 and Lo4j for all my server logs and GWT for client (only AJAX calls). All my unhandled exceptions get logged in my catalina.log.
我对所有服务器日志使用 Tomcat 7 和 Lo4j,对客户端使用 GWT(仅 AJAX 调用)。我所有未处理的异常都记录在我的 catalina.log 中。
Now I want to catch all exceptions and add some of the user's specific Tomcat SessionData.
现在我想捕获所有异常并添加一些用户特定的 Tomcat SessionData。
There are several ways:
有几种方式:
- Try catch over all servlets (there must be a better solution).
- http://tomcat.apache.org/tomcat-7.0-doc/aio.html: I would have to change my connecter, and I don't know if I could use the Tomcat Session within the Event Handler (EventType.ERROR).
- Better way?
- 尝试捕获所有 servlet(必须有更好的解决方案)。
- http://tomcat.apache.org/tomcat-7.0-doc/aio.html:我将不得不更改我的连接器,我不知道是否可以在事件处理程序中使用 Tomcat 会话 (EventType.ERROR) .
- 更好的方法?
What would be the best way to achieve this?
实现这一目标的最佳方法是什么?
采纳答案by Hollerweger
Just Overriding the GWT function doUnexpectedFailure worked.
只需覆盖 GWT 函数 doUnexpectedFailure 即可。
@Override
protected void doUnexpectedFailure(Throwable t) {
ServerLog.error(t.getMessage(), t);
super.doUnexpectedFailure(t);
}
回答by Lyubomyr Shaydariv
Out of what I understood from your question, you can try to use at least one of two ways:
根据我从您的问题中了解到的,您可以尝试使用以下两种方法中的至少一种:
Basic Logging Servlet
基本日志 Servlet
If you have access to the source code of all of your servlets, you can make a little refactoring using a basic super-servlet that is responsible for the logging/whatever of every request working transparently with AJAX, no error forwards directives, and no global exception handlers. Suppose you use service(ServletRequest,ServletResponse)
as the servlet entry point (but you can do the following for every do*()
method either), then you can create an abstract super-servlet and simply inherit your servlets from it.
如果您可以访问所有 servlet 的源代码,则可以使用一个基本的超级 servlet 进行一些重构,该超级 servlet 负责记录/任何与 AJAX 透明工作的请求,没有错误转发指令,也没有全局异常处理程序。假设您service(ServletRequest,ServletResponse)
用作 servlet 入口点(但您也可以对每个do*()
方法执行以下操作),然后您可以创建一个抽象的超级 servlet 并简单地从它继承您的 servlet。
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>stackoverflow.Servlet1</servlet-class>
</servlet>
<servlet>
<servlet-name>servlet2</servlet-name>
<servlet-class>stackoverflow.Servlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>servlet1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet2</servlet-name>
<url-pattern>servlet2</url-pattern>
</servlet-mapping>
public abstract class BasicServlet extends HttpServlet {
/**
* Won't let it be {@code abstract} - we don't want to force any sub-servlet to implement this method.
*/
protected void doService(ServletRequest request, ServletResponse response) {
}
@Override
public final void service(ServletRequest request, ServletResponse response) {
try {
doService(request, response);
} catch ( Throwable ex ) {
err.println(ex.getMessage());
}
}
}
public final class Servlet1 extends BasicServlet {
@Override
protected void doService(ServletRequest request, ServletResponse response) {
out.println("I'm servlet #1");
}
}
public final class Servlet2 extends BasicServlet {
@Override
protected void doService(ServletRequest request, ServletResponse response) {
out.println("I'm servlet #2");
}
}
An advantage of this method is that you do not need to configure anything else than changing your servlet classes and not depend on the external configuration or context. The disadvantage is that you always must extend BasicServlet
.
这种方法的一个优点是,除了更改 servlet 类之外,您不需要配置任何其他内容,并且不依赖于外部配置或上下文。缺点是您必须始终扩展BasicServlet
.
Filter
筛选
I didn't actually test it right now, for more information please see http://docs.oracle.com/javaee/6/api/javax/servlet/Filter.html. Filters allow to intercept each request (we use such a filter implementation for our JSPs while debugging and writing the exceptions into the common log file). The disadvantage is that it's not guaranteed that the filter can cover every exception/case, for example if any filter preceded your own filter.
我现在没有实际测试它,有关更多信息,请参阅http://docs.oracle.com/javaee/6/api/javax/servlet/Filter.html。过滤器允许拦截每个请求(我们在调试和将异常写入公共日志文件时为我们的 JSP 使用这样的过滤器实现)。缺点是不能保证过滤器可以覆盖所有异常/情况,例如,如果任何过滤器位于您自己的过滤器之前。
<filter>
<filter-name>exceptionLoggingFilter</filter-name>
<filter-class>stackoverflow.ExceptionLoggingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>exceptionLoggingFilter</filter-name>
<url-pattern>*</url-pattern> <!-- we will process every request -->
</filter-mapping>
public final class ExceptionLoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) {
try {
filterChain.doFilter(request, response);
} catch ( Throwable ex ) {
err.println(ex);
}
}
@Override
public void destroy() {
}
}
Hope this helps.
希望这可以帮助。
回答by mindas
1) You can define error page for your webapp, like this:
1) 您可以为您的 webapp 定义错误页面,如下所示:
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error</location>
</error-page>
Then you can bind another servlet at /error
and handle the exception there.
然后你可以绑定另一个 servlet/error
并在那里处理异常。
2) You can setUncaughtExceptionHandler
for every HTTP connector thread. You could use this technique with servlet filter which would contain reference to the current HttpRequest
(say, via a thread local). This won't work with async I/O by the way.
2) 您可以setUncaughtExceptionHandler
为每个 HTTP 连接器线程。您可以将此技术与 servlet 过滤器一起使用,该过滤器将包含对当前的引用HttpRequest
(例如,通过本地线程)。顺便说一下,这不适用于异步 I/O。