1

I have a (newbie) question regarding Spring framework, Aspect Orientated Programming and AspectJ.

Is there a way to find out which method caused call to "beforeAdvice" and "afterAdvice" ?

For example , in the example below , can I find out if Dog.bark() or Dog.sleep() caused call to "beforeAdvice" and "afterAdvice" ?

I have attached the console output below the source code.

Thanks for your time and help,
James

Dog.java

package com.tutorialspoint;

public class Dog
{
    public void bark()
    {
        System.out.println("Dog.bark()");
    }

    public void sleep()
    {
        System.out.println("Dog.sleep()");
    }
}

DogMonitor.java

package com.tutorialspoint;

public class DogMonitor
{
    public void beforeAdvice()
    {
        System.out.println("DogMonitor.beforeAdvice()  --  but was it bark or sleep ?");
    }

    public void afterAdvice()
    {
        System.out.println("DogMonitor.afterAdvice()  --  but was it bark or sleep ?");
    }

    public void afterReturningAdvice(Object retVal)
    {
        System.out.println("DogMonitor.afterReturningAdvice(): " + retVal.toString());
    }

    public void AfterThrowingAdvice(IllegalArgumentException ex)
    {
        System.out.println("DogMonitor.AfterThrowingAdvice(): " + ex.toString());
    }
}

MainApp.java

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp
{
   public static void main(String[] args)
   {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

      Dog dog = (Dog) context.getBean("dog");
      dog.bark();
      dog.sleep();
   }
}

Beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

   <aop:config>
      <aop:aspect id="dogMonitorAspect" ref="dogMonitorBean">
         <aop:pointcut  id="selectAll"            expression="execution(* com.tutorialspoint.Dog.*(..))"/>
         <aop:before    pointcut-ref="selectAll"  method="beforeAdvice"/>
         <aop:after     pointcut-ref="selectAll"  method="afterAdvice"/>
      </aop:aspect>
   </aop:config>

   <!-- Definition for dog bean -->
   <bean id="dog" class="com.tutorialspoint.Dog"/>

   <!-- Definition for dogMonitor bean -->
   <bean id="dogMonitorBean" class="com.tutorialspoint.DogMonitor"/>

</beans>

Console output

DogMonitor.beforeAdvice()  --  but was it bark or sleep ?
Dog.bark()
DogMonitor.afterAdvice()  --  but was it bark or sleep ?
DogMonitor.beforeAdvice()  --  but was it bark or sleep ?
Dog.sleep()
DogMonitor.afterAdvice()  --  but was it bark or sleep ?
JamesCollett
  • 179
  • 1
  • 1
  • 7

4 Answers4

2

Try adding a JoinPoint as a parameter to your Aspect methods:

 public void beforeAdvice(JoinPoint jp) {
   // This will print out "bark"
   System.out.println( p.getSignature().getName );
 }

In Spring, this JoinPoint will always have a MethodSignature as a Signature (since spring can only access methods that way), so you can then do (if you want detailed information about the method, more than what the default signature interface tells you)...

MethodSignature signature = (MethodSignature)jp.getSignature();
Method method = signature.getMethod();

And for an Around Aspect, you can use a ProceedingJoinPoint.

Florian Schaetz
  • 10,454
  • 5
  • 32
  • 58
1

You could pull the stack from a new Throwable (that you don't throw). Like so:

StackTraceElement[] stack = new Throwable().getStackTrace();
String methodName = stack[1].getMethodName();
slambeth
  • 887
  • 5
  • 17
  • Ok, after looking it up, seems that the question on how to get the stacktrace isn't that easy... http://stackoverflow.com/questions/1069066/get-current-stack-trace-in-java – Florian Schaetz Aug 20 '15 at 17:37
  • hmmm, I just assumed you were right. :). I'll try pulling it from the current thread like you mentioned next time. I know the method in my answer works, albeit, perhaps it is not the cleanest solution. – slambeth Aug 20 '15 at 17:40
  • Obviously, the JoinPoint solution is much better than the stacktrace, but I'm not so sure about the whole `new Throwable().getStackTrace();` vs. `Thread.getCurrent().getStacktrace();` anymore ;-) – Florian Schaetz Aug 20 '15 at 17:44
1

I had the same problem. I was hoping I could get a getSource method from the JoinPoint but there isn't. I had to look into the stack instead. First I used Thread.dumpStack() to get a sense of what the stack contains. I don't need to go through the entire stack so I created a subset. From the stack contents, I'm interested in the 15-20 range (this depends on you)

StackTraceElement[] subset = Arrays.copyOfRange(Thread.currentThread().getStackTrace(), 15, 20);

Then I printed only what I want

String mypackage = "abc.xwy";
for (int i = 0; i < subset.length; i++) {
  StackTraceElement element = subset[i];
  if (element.getClassName().contains(mypackage) || element.getMethodName().equals(methodName)) {
    System.out.println(element); 
    }
  }
}  
Paul
  • 588
  • 1
  • 4
  • 16
0

Each method can take a JoinPoint as parameter. This object contains all the information about the interception that happened (which method, which class, etc.). For example, the getSignature() method returns the signature of the intercepted method. We can use it to retrieve the name of the method like this:

public void beforeAdvice(JoinPoint joinPoint) {
    System.out.println("DogMonitor.beforeAdvice()");
    System.out.println("I just intercepted method " + joinPoint.getSignature().getName());
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423