I'm using Spring 3.0.5 with an Around aspect.
The @Around aspect works perfectly. The AOP expression targets the interfaces of a bunch of beans.
The aspect executes some logic before and after the invokation:
@Around(...)
public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
// some code
Obj o = pjp.proceed();
// some code
}
No big deal.
Now, I'm trying to create another aspect that throws an exception if the intercepted method takes too long.
private static ExecutorService executor = Executors.newCachedThreadPool();
@Around(...)
public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
Object obj = null;
Callable<Object> task = new Callable<Object>() {
public Object call() {
return pjp.proceed();
}
};
Future<Object> future = executor.submit(task);
try {
obj = future.get(timeout, TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
...
} catch (InterruptedException e) {
// we ignore this one...
} catch (ExecutionException e) {
throw e.getCause(); // rethrow any exception raised by the invoked method
} finally {
future.cancel(true); // may or may not desire this
}
return obj;
}
When I execute the code with only this aspect applied I get the following exception:
java.lang.RuntimeException: java.lang.IllegalStateException: No MethodInvocation found: Check that an AOP invocation is in progress, and that the ExposeInvocationInterceptor is in the interceptor chain.
From the Spring documentation I read:
"Class ExposeInvocationInterceptor
Interceptor that exposes the current MethodInvocation as a thread-local object."
So it looks like that the target got lost because I basically start a new thread and the new thread doesn't have access to thread local. Is there a way to solve this problem or a better approach?
Thanks
The solution was quite trivial. The Aspect that checks how long a method takes must be the last in the "chain" of aspects. I have used the @Order
annotation on the Aspect to make it the last one to be executed.
That did the trick.
If the Aspect is not the last to be executed, the new Thread is not able to access the ThreadLocal variable containing the ExposeInvocationInterceptor
class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With