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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…