java - Spring AOP - 从 catch block 中调用建议

标签 java spring aop spring-aop

目的:在执行业务逻辑时每次发生异常时发送邮件给管理员。

到目前为止,我遇到过“throwing advice”,它很好并且在目标方法引发异常时被执行。

这对我来说可能效果很好,但我必须在设置请求属性和下一页方面做一些额外的处理。我不认为通过使这些对象静态化来共享来自目标类的对象和建议不是一个好主意。代码场景如下图:

try{
   //normal processing
} catch (AuthenticationException ae) {
   ae.printStackTrace();
   req.setAttribute("msg", ae.getMessage());

   //execute advice at this point

   return loginPage;
}

请。看到我想执行建议并相应地提出解决方案的点。

最好的问候

最佳答案

我知道您想避免完整的 AspectJ 而不是 Spring AOP。 (顺便说一句,我想知道为什么很多人都害怕它。)无论如何,在 AspectJ 中,通过 handler() 切入点拦截异常处理程序执行(=catch block )真的很容易。但是有一个限制:它只适用于 before() 建议,不适用于 after()around()。这是由于编译器的限制。查看异常处理程序的 JVM 字节码,您会发现无法检测处理程序 block 的结束。无论如何,因为这个概念与原始问题有关,所以我想在这里展示它是如何完成的。我创建了一个小的驱动程序应用程序和一个非常简单的方面:

import java.util.Random;
import javax.naming.AuthenticationException;

public class Application {
    public static void main(String[] args) {
        Application app = new Application();
        System.out.println(app.foo(1, "two", 3d));
        System.out.println(app.bar("one", 2d, 3));
        System.out.println(app.zot(1d, 2, "three"));
    }

    public String foo(int i, String string, double d) {
        try {
            if (new Random().nextBoolean())
                throw new AuthenticationException("wrong password");
        }
        catch (AuthenticationException e) {
            return "return value from catch block";
        }
        return "normal return value";
    }

    public String bar(String string, double d, int i) {
        try {
            if (new Random().nextBoolean())
                throw new IllegalArgumentException("I don't like your arguments");
        }
        catch (IllegalArgumentException e) {
            return "return value from catch block";
        }
        return "normal return value";
    }

    public String zot(double d, int i, String string) {
        try {
            int n = 2/0;
        }
        catch (Throwable t) {
            return "return value from catch block";
        }
        return "normal return value";
    }
}

如您所见,方法 foobar 根据 ca 中的随机值抛出异常。 50% 的情况,而 zot 总是抛出被零除异常。因此每次运行的输出都会不同。

那么,如果所有的异常都被静静地吞下并且没有被记录下来,我们如何找出发生了什么?像这样:

import java.util.logging.Logger;

public aspect ExceptionLoggingAspect {
    final Logger log = Logger.getLogger(ExceptionLoggingAspect.class.getName());

    before(Throwable t) : handler(Throwable+) && args(t) {
        log.warning(thisJoinPointStaticPart + "  ->  " + t);
    }
}

这非常简单优雅,适用于您的整个应用程序。这是一些测试输出:

Apr 6, 2013 12:15:43 PM ExceptionLoggingAspect ajc$before$ExceptionLoggingAspect$1$3d90b181
WARNING: handler(catch(AuthenticationException))  ->  javax.naming.AuthenticationException: wrong password
return value from catch block
Apr 6, 2013 12:15:43 PM ExceptionLoggingAspect ajc$before$ExceptionLoggingAspect$1$3d90b181
WARNING: handler(catch(IllegalArgumentException))  ->  java.lang.IllegalArgumentException: I don't like your arguments
return value from catch block
Apr 6, 2013 12:15:43 PM ExceptionLoggingAspect ajc$before$ExceptionLoggingAspect$1$3d90b181
WARNING: handler(catch(Throwable))  ->  java.lang.ArithmeticException: / by zero
return value from catch block

在建议中你可以做更多,例如访问 this 并读取/更新一些属性等。

关于java - Spring AOP - 从 catch block 中调用建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15473725/

相关文章:

java - 获取泛型类的类类型

java - MyFacesServlet 包装器中的 FacesMessages

java - 如何将泛型类型用作返回值并将泛型类型用作参数?

java - 侦探日志 traceId 未传播到其他服务

java - AspectJ - 无法覆盖切入点 - 参数类型不匹配

java - 在 Spring 中使用 AspectJ 捕获映射器方法内的 setter

java - TestNG - 为什么 testNG 报告器不打印出 else 语句?

java - JPA 保留的 OffsetDateTime 相差 2 小时

java - Spring:使用声明的多个调度程序访问正确的 WebApplicationContext

java - Spring更改cglib