【问题标题】:AOP Exception HandlingAOP 异常处理
【发布时间】:2012-06-12 11:01:06
【问题描述】:

我看到 Guice 和 Spring 在后台使用 AOP Alliance 进行方法拦截,我一直在试图弄清楚如何让 AOP Alliance 拦截和处理某些异常,所以我不必继续写相同的东西在每个 catch 块中一遍又一遍地编写代码。

但是看完剧本后,好像AOP联盟并没有提供任何方法来拦截抛出的Throwables,使得处理程序/拦截器可以做一些事情(记录异常等)然后确定是否进一步传播异常或只是恢复到引发异常的行之后的下一行

HerpDerp hd = null;

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

Manny.pacquiao();

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

  • 如果在 Java 中无法做到这一点,请告诉我
  • 无论是否可以在 Java 中执行此操作,有没有办法通过 AOP 联盟拦截抛出的异常,或者我必须去其他地方。如果我必须去别的地方,在哪里?方面J?

谢谢!

【问题讨论】:

    标签: java exception-handling aop


    【解决方案1】:

    您可以使用 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.");
        }
    }
    }
    

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        要使用 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
        }
        

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

        【讨论】:

        • 谢谢@Wim - AOP Alliance 无法进行这样的基于 AOP 的异常处理吗?
        • 我不这么认为。如果您检查spring docs,它会显示:Join point: a point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.
        • ConstructorInterceptor 是否会以某种方式被破解以拦截异常(在构造时)?
        【解决方案4】:

        @4herpsand7derpsago 如果你试图做的是使用 AOP 捕获抛出的异常以执行各种任务来处理它,然后回到最初抛出异常的代码,我想你错过了理解 AOP 的概念.

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

        HerpDerp hd = null;
        
        if(hd == null)
        throw new RuntimeException("Herpyl derp!");
        
        Manny.pacquiao();
        

        如果您希望 AOP 捕获您的 RuntimeException,执行一些处理它并返回到 Manny.pacquiao();,答案是 您不能。 原因是当RuntimeException 被AOP 抛出并捕获时,堆栈已经在您的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之前

        【讨论】:

          猜你喜欢
          • 2017-01-27
          • 1970-01-01
          • 2014-09-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-04
          • 1970-01-01
          相关资源
          最近更新 更多