本文介绍了Spring AOP - 从 catch 块调用建议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目的:每次在执行业务逻辑时发生异常时向管理员发送电子邮件.

Purpose: Send an email to admin every time an exception occurs while executing business logic.

到现在为止,我遇到了抛出建议",这很好,并且会在目标方法引发异常时执行.

Till now I have come across "throwing advice" which is fine and gets executed when an exception is raised from the target method.

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

This could have worked well for me but I have to do some additional processing in terms of setting request attribute and next page. I don't think it would be a good idea to share the objects from target class with advice by making those objects static. The code scenario is shown below:

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

   //execute advice at this point

   return loginPage;
}

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

Pls. see the point where I want to execute the advice and suggest solution accordingly.

最好的问候

推荐答案

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

I know you want to avoid full AspectJ as opposed to Spring AOP. (BTW, I wonder why many people are so afraid of it.) Anyway, in AspectJ is is really easy to intercept exception handler execution (=catch blocks) by means of the handler() pointcut. There is one limitation though: It only works with before() advice, not after() or around(). This is due to compiler limitations. Look at JVM byte code of exception handlers and you will see that there is no way to detect the end of a handler block. Anyway, because the concept is related to the original question, I want to show here how it is done. I have created a little driver application and a very simple aspect:

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 总是抛出除以零异常.所以输出会因运行而异.

As you can see, methods foo and bar throw exceptions based on random values in ca. 50% of all cases, whereas zot always throws a division by zero exception. So the output will differ from run to run.

那么如果所有异常都被静默吞下而不被记录,我们如何找出发生了什么?像这样:

So how do we find out what is going on if all exceptions are silently swallowed and not logged? Like so:

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

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

This is really simple and elegant and works throughout your application. Here is some test output:

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 并读取/更新一些属性等等.

In the advice you can do more, e.g. access this and read/update some properties and so fort.

这篇关于Spring AOP - 从 catch 块调用建议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-06 04:16