如何检测Java中何时全局抛出了异常?
如何检测何时在应用程序中的任何地方引发了异常?
每当Java桌面应用程序中的任何地方引发异常时,我都会尝试自动发送电子邮件给自己。我认为通过这种方式我可以更加主动。
我知道只要发生异常,我都可以明确地记录日志并通知自己,但是我必须在所有地方都做,而且我可能(很可能会)错过一对夫妇。
有什么建议?
解决方案
回答
在这种情况下,我认为最好的选择是编写一个自定义类加载器以处理应用程序中的所有类加载,并且每当请求异常类时,我们都将返回包装所请求的异常类的类。该包装器调用包装的异常,但也记录异常事件。
回答
Java 1.5中新的调试钩子使我们可以执行此操作。它启用例如调试器中的"在任何异常情况下中断"。
这是我们需要的特定Javadoc。
回答
签出Thread.UncaughtExceptionHandler。我们可以为每个线程设置它,也可以为整个VM设置默认值。
这至少可以找到想念的人。
回答
如果我们使用的是Spring之类的Web框架,则可以在web.xml中委派一个页面,然后使用控制器发送电子邮件。例如:
在web.xml中:
<error-page> <error-code>500</error-code> <location>/error/500.htm</location> </error-page>
然后将/error/500.htm定义为控制器。我们可以从参数javax.servlet.error.exception访问该异常:
Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
如果我们只是在运行常规Java程序,那么我想我们会陷入公共静态void main(String [] args){试试{...} catch(Exception e){}}
回答
我假设我们不是任何异常,而是任何未捕获的异常。
在这种情况下,Sun网站上的这篇文章有一些想法。我们需要将顶级方法包装在try-catch
块中,还需要做一些额外的工作来处理其他线程。
回答
我们可能不想在任何例外情况下寄出邮件。 JDK中有很多代码实际上依赖于异常才能正常工作。我认为我们更感兴趣的是未捕获的例外。如果我们正在捕获异常,则应该在那里处理通知。
在桌面应用程序中,有两个地方需要担心这一点,即事件调度线程(EDT)和EDT之外。在全局上,我们可以注册一个实现java.util.Thread.UncaughtExceptionHandler的类,并通过java.util.Thread.setDefaultUncaughtExceptionHandler对其进行注册。如果异常结束到堆栈的底部并且该线程尚未在该线程或者ThreadGroup的当前线程实例上设置处理程序,则将调用此方法。
EDT有一个处理异常的不同钩子。需要使用零参数构造函数的类的完全合格的类名注册系统属性'sun.awt.exception.handler'。此类需要一个实例方法handle(Throwable
)来完成工作。返回类型无关紧要,并且由于每次都会创建一个新实例,因此不要指望保持状态。
因此,如果我们不在乎哪个线程,则示例中发生的异常可能看起来像这样:
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
方法,我们应该已经准备就绪。
回答
如果遇到运行时异常(例如OutOfMemoryError或者StackOverflow),则可能无法发送电子邮件。我们很有可能必须生成另一个进程并捕获由它引发的任何异常(使用上述各种技术)。
回答
如果使用的是Java 1.3 / 1.4,则Thread.UncaughtExceptionHandler不可用。
在这种情况下,可以使用基于AOP的解决方案在引发异常时触发一些代码。 Spring和/或者AspectJ可能会有所帮助。