JamesCollett
JamesCollett

Reputation: 189

Spring , AOP , AspectJ :- is there a way to find out which method caused call to "beforeAdvice" and "afterAdvice"

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 ?

Upvotes: 1

Views: 2618

Answers (4)

Paul
Paul

Reputation: 598

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); 
    }
  }
}  

Upvotes: 1

Florian Schaetz
Florian Schaetz

Reputation: 10652

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.

Upvotes: 2

Tunaki
Tunaki

Reputation: 137064

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());
}

Upvotes: 0

slambeth
slambeth

Reputation: 897

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();

Upvotes: 1

Related Questions