I am (of course) trying to maintain a project using many constructs I don't know that well. In the course of attempting to figure out the AOP use within Spring, I came across methods with the following annotation:
@Around(value = "@annotation(annotation)")
So @Around means we're doing the 'around' version of the method pointcut in AOP, I understand that. I don't know what the other part means. The Spring documentation gives the following:
@annotation - limits matching to join points where the subject of the
join point (method being executed in Spring AOP) has the given
annotation
I don't know what that means - "method being executed in Spring AOP" sounds like the advised method, but I don't know how I (or Spring) figure out which methods are being advised. It sounds like it is the methods that have "the given annotation", but if so, what annotation has been given?
What methods are advised by this annotation? And what else does it mean?
if you have the following Spring Bean:
@Component
public class foo {
@com.pkg.Bar
void fooMe() {
}
}
Then the following Advice:
@Around("@annotation(com.pkg.Bar)")
Will invoke the interceptor around fooMe
(or any other Spring bean method annotated with @Bar
)
The @Transactional
annotation is a good example
You would have a parameter named annotation
, of the appropriate type. It's called bound annotation, see this excerpt from the Spring AOP documentation:
The following example shows how you could match the execution of
methods annotated with an @Auditable annotation, and extract the audit
code.
First the definition of the @Auditable
annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {
AuditCode value();
}
And then the advice that matches the execution of @Auditable
methods:
@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
public void audit(Auditable auditable) {
AuditCode code = auditable.value();
// ...
}
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class TimeLoggingAspect {
@Before("timeLoggingAspect()")
public void logBefore(JoinPoint joinPoint){
System.out.println("Method Name="+joinPoint.getSignature().getName());
System.out.println("Logging Before...");
}
/*
// Other way for AOP implemetation
@Pointcut("execution(public void userService())")
public void timeLoggingAspect(){
}
@After("timeLoggingAspect()")
public void logAfter() throws Exception{
System.out.println("Logging After...");
throw new Exception("Error after Logging");
}
@AfterThrowing(pointcut="timeLoggingAspect()",throwing="exception")
public void logAfterThrowingException(Exception exception){
System.out.println(exception.getLocalizedMessage());
}*/
}
/** Config class **/
import org.springframework.stereotype.Component;
import com.annotation.EnableMethodVisit;
@Component
@EnableMethodVisit
public class UserService {
public void userService(){
System.out.println("user service calling......");
}
}
/** Custom Annotation are used **/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableMethodVisit {
}
/** UserService **/
import org.springframework.stereotype.Component;
import com.annotation.EnableMethodVisit;
@Component
@EnableMethodVisit
public class UserService {
public void userService(){
System.out.println("user service calling......");
}
}
/** AOP Test **/
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.aop.classes.UserService;
public class SpringAopTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AspectConfig.class);
ctx.refresh();
UserService userService = ctx.getBean(UserService.class);
userService.userService();;
}
}
if you have the following Spring Bean:
@Component
public class foo {
@com.pkg.Bar
void fooMe() {
}
}
and the following @interface:
public @interface Bar {
String value() default "default value";
}
you can use the following Advice:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class BarAop {
@Around(value = "@annotation(bar)") // This 'bar' is one of the parameters of method around(point, bar)
public Object around(ProceedingJoinPoint point, Bar bar) throws Throwable {
String value = bar.value();
System.out.println(value); // will print "default value"
// execute target method
Object object = point.proceed();
System.out.println("return : " + object);
return object;
}
}