Spring AOP - Invoking advice from catch block

前端 未结 4 498
我在风中等你
我在风中等你 2020-12-19 16:26

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

4条回答
  •  不知归路
    2020-12-19 16:50

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

    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
    

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

提交回复
热议问题