I am learning Spring and I searched a lot about how to properly use @args() AspectJ designator but I am still not clear completely. What I know about it is that it limits joint-point matches to the execution of methods whose arguments are annoted with the given annotation types. This does not seem to work in my case.
So here goes my files:
Human.java
@Component
public class Human {
int sleepHours;
public int sleep(String sleepHours) {
this.sleepHours = Integer.parseInt(sleepHours);
System.out.println("Humans sleep for " + this.sleepHours + " hours.");
return this.sleepHours+1;
}
}
Sleepable.java - Sleepable annotation
package com.aspect;
public @interface Sleepable {
}
SleepingAspect.java - Aspect
@Component
@Aspect
public class SleepingAspect {
@Pointcut("@args(com.aspect.Sleepable)")
public void sleep(){};
@Before("sleep()")
public void beforeSleep() {
System.out.println("Closing eyes before sleeping");
}
@AfterReturning("sleep()")
public void afterSleep() {
System.out.println("Opening eyes after sleep");
}
}
MainApp.java
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Human human = (Human) context.getBean("human");
@Sleepable
String sleepHours = "8";
human.sleep(sleepHours);
}
}
Output
Humans sleep for 8 hours.
Expected Output
Closing eyes before sleeping
Humans sleep for 8 hours.
Opening eyes after sleep
You have several mistakes in your code:
public int sleep(String sleepHours)
.@Retention(RetentionPolicy.RUNTIME)
.@args
is the wrong pointcut type. It captures method arguments the types of which are annotated. You want to use @annotation(com.aspect.Sleepable)
instead.I think you should not try a copy & paste cold start with Spring AOP but read the Spring AOP manual first. Everything I explained here can be found there.
Update: So according to you comments you were just practicing and trying to make up an example for @args()
. Here is one in plain AspectJ. You can easily use it in similar form in Spring AOP. The @Before
advice shows you how to match on an argument with an annotation on its class, the @After
advice also shows how to bind the corresponding annotation to an advice argument.
Annotation + class using it:
package com.company.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}
package com.company.app;
@MyAnnotation
public class MyClass {}
Driver application:
package com.company.app;
public class Application {
public static void main(String[] args) {
new Application().doSomething(new MyClass(), 11);
}
public String doSomething(MyClass myClass, int i) {
return "blah";
}
}
As you can see, here we use the annotated class MyClass
in a method argument. This can be matched with @args()
in the following aspect.
Aspect:
package com.company.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import com.company.app.MyAnnotation;
@Aspect
public class MyAspect {
@Before("@args(com.company.app.MyAnnotation, ..)")
public void myBeforeAdvice(JoinPoint thisJoinPoint) {
System.out.println("Before " + thisJoinPoint);
}
@After("@args(myAnnotation, ..)")
public void myAfterAdvice(JoinPoint thisJoinPoint, MyAnnotation myAnnotation) {
System.out.println("After " + thisJoinPoint + " -> " + myAnnotation);
}
}
Console log:
Before call(String com.company.app.Application.doSomething(MyClass, int))
Before execution(String com.company.app.Application.doSomething(MyClass, int))
After execution(String com.company.app.Application.doSomething(MyClass, int)) -> @com.company.app.MyAnnotation()
After call(String com.company.app.Application.doSomething(MyClass, int)) -> @com.company.app.MyAnnotation()
Of course, call()
joinpoints are unavailable in Spring AOP, so there you would only see two lines of log output.