如何检测何时在 Java 中全局抛出异常?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/75218/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:57:26  来源:igfitidea点击:

How can I detect when an Exception's been thrown globally in Java?

javaexception

提问by Allain Lalonde

How can I detect when an Exception has been thrown anywhere in my application?

如何检测何时在我的应用程序中的任何地方抛出异常?

I'm try to auto-magically send myself an email whenever an exception is thrown anywhere in my Java Desktop Application. I figure this way I can be more proactive.

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

I know I could just explicitly log and notify myself whenever an exception occurs, but I'd have to do it everywhere and I might(more likely will) miss a couple.

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

Any suggestions?

有什么建议?

回答by shemnon

You probobly don't want to mail on any exception. There are lots of code in the JDK that actaully depend on exceptions to work normally. What I presume you are more inerested in are uncaught exceptions. If you are catching the exceptions you should handle notifications there.

您可能不想邮寄任何异常。JDK 中有很多代码实际上依赖于异常才能正常工作。我认为您更感兴趣的是未捕获的异常。如果您正在捕获异常,您应该在那里处理通知。

In a desktop app there are two places to worry about this, in the event-dispatch-thread(EDT) and outside of the EDT. Globaly you can register a class implementing java.util.Thread.UncaughtExceptionHandlerand register it via java.util.Thread.setDefaultUncaughtExceptionHandler. This will get called if an exception winds down to the bottom of the stack and the thread hasn't had a handler set on the current thread instance on the thread or the ThreadGroup.

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

The EDT has a different hook for handling exceptions. A system property 'sun.awt.exception.handler'needs to be registerd with the Fully Qualified Class Name of a class with a zero argument constructor. This class needs an instance method handle(Throwable) that does your work. The return type doesn't matter, and since a new instance is created every time, don't count on keeping state.

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

So if you don't care what thread the exception occurred in a sample may look like this:

因此,如果您不关心样本中发生的异常是哪个线程,则可能如下所示:

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());
  }
}

Add this class into some random package, and then call the registerExceptionHandlermethod and you should be ready to go.

将该类添加到某个随机包中,然后调用该registerExceptionHandler方法,您就可以开始使用了。

回答by Jason Cohen

The new debugging hooks in Java 1.5 let you do this. It enables e.g. "break on any exception" in debuggers.

Java 1.5 中的新调试挂钩可以让您做到这一点。它可以在调试器中启用例如“中断任何异常”。

Here's the specific Javadocyou need.

这是您需要的特定 Javadoc

回答by Justin Rudd

Check out Thread.UncaughtExceptionHandler. You can set it per thread or a default one for the entire VM.

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

This would at least help you catch the ones you miss.

这至少会帮助你抓住那些你错过的人。

回答by Mat Mannion

If you're using a web framework such as Springthen you can delegate in your web.xml to a page and then use the controller to send the email. For example:

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

In web.xml:

在 web.xml 中:

<error-page>
  <error-code>500</error-code>
  <location>/error/500.htm</location>
</error-page>

Then define /error/500.htm as a controller. You can access the exception from the parameter javax.servlet.error.exception:

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

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

If you're just running a regular Java program, then I would imagine you're stuck with public static void main(String[] args) { try { ... } catch (Exception e) {} }

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

回答by Alexandre Victoor

If you are using java 1.3/1.4, Thread.UncaughtExceptionHandler is not available. In this case you can use a solution based on AOP to trigger some code when an exception is thrown. Spring and/or aspectJ might be helpful.

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

回答by Alex Fedulov

In my current project I faced the similar requirement regarding the errors detection. For this purpose I have applied the following approach: I use log4j for logging across my app, and everywhere, where the exception is caught I do the standard thing: log.error("Error's description goes here", e);, where e is the Exception being thrown (see log4j documentation for details regarding the initialization of the "log"). In order to detect the error, I use my own Appender, which extends the log4j AppenderSkeleton class:

在我当前的项目中,我面临着关于错误检测的类似要求。为此,我采用了以下方法:我使用 log4j 在我的应用程序中记录日志,并且在捕获异常的任何地方我都做标准的事情: log.error("Error's description goes here", e);,其中 e 是抛出的异常(有关初始化的详细信息,请参阅 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;
        }
    }
}

The log4j configuration file has to just contain a definition of the new appender and its attachement to the selected logger (root in my case):

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

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

You can either call the errorsOccured() method of the ErrorsDetectingAppender at some significant point in your programs's execution flow or react immidiately by adding functionality to the if block in the append() method. This approach is consistent with the semantics: things that you consider errors and log them as such, are detected. If you will later consider selected errors not so important, you just change the logging level to log.warn() and report will not be sent.

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

回答by Raedwald

There is simply no good reason to be informed of every thrown exception. I guess you are assuming that a thrown exception indicates a "problem" that your "need" to know about. But this is wrong. If an exception is thrown, caught and handled, all is well. The only thing you needto be worried about is an exception that is thrown but not handled (not caught). But you can do that in a try...catchclause yourself.

没有充分的理由被告知每个抛出的异常。我猜您假设抛出的异常表示您“需要”了解的“问题”。但这是错误的。如果抛出、捕获和处理异常,则一切正常。您唯一需要担心的是抛出但未处理(未捕获)的异常。但是你可以自己在try...catch子句中做到这一点。

回答by Dave Webb

I assume you don't mean anyException but rather any uncaughtException.

我假设您的意思不是任何异常,而是任何未捕获的异常。

If this is the case this article on the Sun Websitehas some ideas. You need to wrap your top level method in a try-catchblock and also do some extra work to handle other Threads.

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

回答by toluju

In this case I think your best bet might be to write a custom classloader to handle all classloading in your application, and whenever an exception class is requested you return a class that wraps the requested exception class. This wrapper calls through to the wrapped exception but also logs the exception event.

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

回答by Nik

Sending an email may not be possible if you are getting a runtime exception like OutOfMemoryError or StackOverflow. Most likely you will have to spawn another process and catch any exceptions thrown by it (with the various techniques mentioned above).

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