Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Aspect fails when join point is invoked in new thread

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

like image 768
Luciano Fiandesio Avatar asked Nov 04 '22 15:11

Luciano Fiandesio


1 Answers

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.

like image 122
Luciano Fiandesio Avatar answered Nov 12 '22 17:11

Luciano Fiandesio