23

我看到 Guice 和 Spring 在后台使用 AOP Alliance 进行方法拦截,我一直在试图弄清楚如何让 AOP Alliance 拦截和处理某些异常,这样我就不必继续编写相同的代码了在每个catch街区内重新来过。

但是看了下戏,好像AOP联盟并没有提供任何拦截 throwedThrowable的方式,让handler/interceptor可以做一些事情(记录异常等),然后判断是否传播进一步的异常或只是恢复到引发异常的行之后的下一行

HerpDerp hd = null;

if(hd == null)
    throw new RuntimeException("Herpyl derp!");

Manny.pacquiao();

我正在寻找一种 AOP 异常处理机制,它会拦截并使用业务逻辑来决定是继续传播它还是在调用RuntimeException时恢复它。Manny.pacquioa()

  • 如果在 Java 中无法做到这一点,请告诉我
  • 不管它是否可以在 Java 中做到这一点,有没有办法用 AOP 联盟拦截抛出的异常,或者我必须去别的地方。如果我必须去别的地方,在哪里?方面J?

谢谢!

4

4 回答 4

40

您可以使用 Spring AOP 捕获异常,但我不知道这是否符合您对纯 Java 框架的要求。

使用 Spring,您可以编写一个简单的 AOP 拦截器,如下所示:

@Aspect
public class ErrorInterceptor{
@AfterThrowing(pointcut = "execution(* com.mycompany.package..* (..))", throwing = "ex")
public void errorInterceptor(WidgetException ex) {
    if (logger.isDebugEnabled()) {
        logger.debug("Error Message Interceptor started");
    }

    // DO SOMETHING HERE WITH EX
    logger.debug( ex.getCause().getMessage());


    if (logger.isDebugEnabled()) {
        logger.debug("Error Message Interceptor finished.");
    }
}
}

但是没有办法返回调用方法或在下一行继续处理。但是,如果您在这里处理异常,除非您自己重新抛出它,否则它不会冒泡。

于 2012-06-11T15:16:48.380 回答
4

这不存在是有原因的。这将需要重写代码的块结构,就好像您首先编写了 try/catch 块一样。在我看来,这可能会对变量范围和其他事物造成严重破坏。您要求 AOP 将字节码重写为类似于以下代码的内容,这是相当大的重写。

HerpDerp hd = null;

try {
    if(hd == null)
        throw new RuntimeException("Herpyl derp!");
} catch(RuntimeException e) {
   if (someConditionIsMet) {
       throw e;
   }
}

Manny.pacquiao();
于 2012-06-11T15:36:08.450 回答
2

@4herpsand7derpsago 如果您要做的是使用 AOP 捕获抛出的异常以执行各种任务来处理它,然后返回最初抛出异常的代码,我认为您错过了理解 AOP 的概念。

正如您在代码中指出的那样

HerpDerp hd = null;

if(hd == null)
throw new RuntimeException("Herpyl derp!");

Manny.pacquiao();

如果您希望 AOP 捕获您的RuntimeException,执行一些东西来处理它并返回Manny.pacquiao();,答案是您不能。原因是当RuntimeExceptionAOP 抛出并捕获 时,堆栈已经在您的 AOP 代码中。你不能回来执行Many.pacquiao();。如果要继续执行,唯一的方法Many.pacquiao();是使用try-finally块如下

HerpDerp hd = null;

try {
    if(hd == null)
        throw new RuntimeException("Herpyl derp!");
} finally {
    Manny.pacquiao();
}

只有这样你Many.pacquiao()才会被执行,但在你的 AOP 捕获之前RuntimeException

于 2012-06-14T02:57:44.447 回答
2

要使用 AspectJ “捕获”未捕获的异常,您可以使用以下方面:

pointcut uncaughtExceptionScope() : 
    (execution(* com.mycompany.myrootpackage..Main.main(..)) 
    || execution(* java.util.concurrent.Callable+.call()) 
    || execution(* java.lang.Runnable+.run()) 
    ));

after() throwing(Throwable t) : uncaughtExceptionScope() && !cflow(adviceexecution())    {
    handleException(thisJoinPoint, t);
}   

protected void handleException(JoinPoint jp, Throwable t)
{
    // handle exception here
}

我认为不可能“回到”执行点。

于 2012-06-08T12:04:25.103 回答