问题
I'm trying to imitate Spring's AspectJ @Async support but with a message bus.
The issue is I need to know if my Message Bus (RabbitMQ MessageListener) is calling the method or a normal (all others) caller where the method will return instantly.
My annotation is called @MQAsync instead of Springs @Async.
package com.snaphop.mqueue;
import org.apache.log4j.Logger;
import com.snaphop.mqueue.MQAsync;
public aspect MQAsyncAspect {
//pointcut asyncTypeMarkedMethod() : execution(@MQAsync void *(..));
pointcut asyncTypeMarkedMethod() : call(@MQAsync void *(..));
private static final Logger log = Logger.getLogger("MQAsync");
Object around() : asyncTypeMarkedMethod() {
if (listenerIsCaller) {
return proceed();
}
//Send the method parameters to the message bus.
//this logic isn't here for brevity.
return null;
}
}
The call pointcut will get me the caller context but that will not work as I will be calling the method with my message listener through reflection. The execution pointcut (commented out) will not tell me who is calling the method.
Is there a way to determine the caller class maybe through some sort of stack dump analysis?
回答1:
You can determine which class is invoking the current method with the following call. Note that you'll have to catch ClassNotFoundException
(unless you're satisfied simply retrieving the name as a String
).
Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
Why the third element? Because the stack is ordered like so when the stack trace method is invoked:
Thread#getStackTrace()
CurrentClass.currentMethod
()
ParentClass.parentMethod
()
回答2:
Actually cheeken's answer is nice, but for AspectJ call()
pointcuts you can get the calling class much more easily and without ugly reflection:
thisEnclosingJoinPointStaticPart.getSignature().getDeclaringType()
Please consider to accept this answer if you think it is better than the other one, otherwise just enjoy the power of AspectJ. ;-)
回答3:
This is an alternative that seems more light since is native and commonly used by the SecurityManager. To use it we need a utility class because the the method we need is protected.
public class CallStackUtils extends SecurityManager {
static CallStackUtils sm = new CallStackUtils();
public Class[] getCallersClassesStack0() {
return getClassContext();
}
static public Class[] getCallersClassesStack() {
return sm.getCallersClassesStack0();
}
}
来源:https://stackoverflow.com/questions/10924675/knowing-caller-class-with-aspectj