如何检测Java中全局抛出exception的时间?

如何在应用程序中的任何位置检测到exception何时被抛出?

每当我的Java桌面应用程序中的任何地方抛出exception时,我都会尝试自动向我发送电子邮件。 我这样想,我可以更积极主动。

我知道我可以在发生exception时明确地记录并通知我自己,但我必须在任何地方都这样做,我可能(更有可能)会错过一对。

有什么建议么?

你可能不希望邮寄任何exception。 JDK中有很多代码,它们依赖于exception才能正常工作。 我认为你更不感兴趣的是未被捕获的例外。 如果要捕获exception,则应在此处理通知。

在桌面应用程序中,有两个地方需要担心,在事件调度线程 (EDT)和EDT之外。 全局,您可以注册一个实现java.util.Thread.UncaughtExceptionHandler的类,并通过java.util.Thread.setDefaultUncaughtExceptionHandler注册它。 如果exception结束到堆栈的底部并且线程没有在线程或ThreadGroup上的当前线程实例上设置处理程序,则会调用此方法。

EDT有一个不同的钩子来处理exception。 需要使用零参数构造函数的类的完全限定类名注册系统属性'sun.awt.exception.handler' 。 这个类需要一个实现你的工作的实例方法句柄( Throwable )。 返回类型无关紧要,因为每次都会创建一个新实例,所以不要指望保持状态。

因此,如果您不关心样本中发生exception的线程可能如下所示:

 class ExceptionHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { handle(e); } public void handle(Throwable throwable) { try { // insert your e-mail code here } catch (Throwable t) { // don't let the exception get thrown out, will cause infinite looping! } } public static void registerExceptionHandler() { Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler()); System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName()); } } 

将此类添加到一些随机包中,然后调用registerExceptionHandler方法,您应该准备好了。

Java 1.5中的新调试挂钩允许您执行此操作。 它允许例如在调试器中“中断任何exception”。

这是您需要的特定Javadoc 。

查看Thread.UncaughtExceptionHandler 。 您可以为每个线程设置它,也可以为整个VM设置默认值。

这至少可以帮助你抓住你想念的那些。

如果您使用的是java 1.3 / 1.4,则Thread.UncaughtExceptionHandler不可用。 在这种情况下,您可以使用基于AOP的解决方案在抛出exception时触发某些代码。 Spring和/或aspectJ可能会有所帮助。

在我目前的项目中,我遇到了关于错误检测的类似要求。 为此我已经应用了以下方法:我使用log4j来记录我的应用程序,并且在任何地方,exception被捕获我做标准的事情: log.error("Error's description goes here", e); ,其中e是抛出的exception(有关“log”初始化的详细信息,请参阅log4j文档)。 为了检测错误,我使用自己的Appender,它扩展了log4j AppenderSkeleton类:

 import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.spi.LoggingEvent; public class ErrorsDetectingAppender extends AppenderSkeleton { private static boolean errorsOccured = false; public static boolean errorsOccured() { return errorsOccured; } public ErrorsDetectingAppender() { super(); } @Override public void close() { // TODO Auto-generated method stub } @Override public boolean requiresLayout() { return false; } @Override protected void append(LoggingEvent event) { if (event.getLevel().toString().toLowerCase().equals("error")) { System.out.println("-----------------Errors detected"); this.errorsOccured = true; } } } 

log4j配置文件必须只包含新appender的定义及其对所选记录器的附件(在我的情况下为root):

 log4j.rootLogger = OTHER_APPENDERS, ED log4j.appender.ED=com.your.package.ErrorsDetectingAppender 

您可以在程序执行流程中的某个重要位置调用ErrorsDetectingAppender的errorsOccured()方法,也可以通过在append()方法中向if块添加function来做出反应。 这种方法与语义一致:检测到您认为错误并将其记录的事物。 如果稍后您将考虑选择的错误并不那么重要,您只需将日志记录级别更改为log.warn()并且不会发送报告。

在这种情况下,我认为您最好的选择是编写一个自定义类加载器来处理应用程序中的所有类加载,并且每当请求exception类时,您都会返回一个包装请求的exception类的类。 此包装器调用包装的exception,但也记录exception事件。

如果您正在使用诸如Spring之类的Web框架,那么您可以在web.xml中委派给页面,然后使用控制器发送电子邮件。 例如:

在web.xml中:

  500 /error/500.htm  

然后将/error/500.htm定义为控制器。 您可以从参数javax.servlet.error.exception访问exception:

 Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception"); 

如果你只是运行一个普通的Java程序,那么我想你会遇到public static void main(String [] args){try {…} catch(Exception e){}}

我假设你不是指任何exception,而是任何未被捕获的exception。

如果是这种情况,Sun网站上的这篇文章有一些想法。 您需要将顶级方法包装在try-catch块中,并且还需要做一些额外的工作来处理其他线程。

如果您收到OutOfMemoryError或StackOverflow等运行时exception,则可能无法发送电子邮件。 很可能你必须产生另一个进程并捕获它抛出的任何exception(使用上面提到的各种技术)。