我使用Spring 3.0.5和Around方面。
@Around方面非常有效。 AOP表达式针对一堆bean的接口。
方面在invokation之前和之后执行一些逻辑:
@Around(...)
public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
// some code
Obj o = pjp.proceed();
// some code
}
没什么大不了的。
现在,我试图创建另一个方面,如果截获的方法花费太长时间会引发异常。
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;
}
当我执行仅应用此方面的代码时,我得到以下异常:
java.lang.RuntimeException:java.lang.IllegalStateException:No 找到MethodInvocation:检查AOP调用是否正在进行中, 并且ExposeInvocationInterceptor位于拦截器链中。
从Spring documentation我读到:
&#34; Class ExposeInvocationInterceptor
将当前MethodInvocation公开为线程局部对象的拦截器。&#34;
所以看起来目标丢失了,因为我基本上开始一个新线程并且新线程无法访问本地线程。有没有办法解决这个问题或更好的方法?
由于
答案 0 :(得分:2)
解决方案非常简单。检查方法花费时间的方面必须是方面“链”中的最后一个方面。我在Aspect上使用了@Order
注释,使其成为最后一个要执行的注释。
这就是诀窍。
如果Aspect不是最后一个要执行的,则新线程无法访问包含ExposeInvocationInterceptor
类的ThreadLocal变量。
答案 1 :(得分:0)
如果pjp.proceed()
调用适合中断,您可以尝试从另一个线程中断当前线程。例如。你的方面看起来像:
new Interrupter(Thread.currentThread()).start();
// Following call will get interrupted if it takes too long
try {
return pjp.proceed();
} catch (InterruptedException ex) {
// do something?
}
中断类的类似于:
static class Interrupter extends Thread {
private final Thread other;
Interrupter(final Thread other) {
this.other = other;
}
@Override
public void run() {
try {
Thread.sleep(500); // or whatever your timeout is
} catch (final InterruptedException e) {
e.printStackTrace();
}
if (other.isAlive()) {
other.interrupt();
}
}
}