Description
Affects: spring-aop:5.0.9.RELEASE, spring-boot-starter-aop:2.0.5.RELEASE
public interface FooService {
@MyAnnotation
void hello();
}
public class FooServiceImpl implements FooService {
void hello();
}
public class MyAspect {
@Pointcut("@annotation(MyAnnotation")
public void myPointcut() {
}
@Around("myPointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
...
}
}
@Configuration
public class MyAopConfiguration {
@Bean
public MyAspect myAspect () {
return new MyAspect();
}
}
Using spring-aop
like the code above, it doesn't work, around(ProceedingJoinPoint pjp)
never executes.
If put the @MyAnnotation
on the implemented method of FooServiceImpl
, it works.
public interface FooService {
void hello();
}
public class FooServiceImpl implements FooService {
@MyAnnotation
void hello();
}
Learned from two questions in Stack Overflow:
- https://stackoverflow.com/questions/6594457/aspectj-annotation-pointcut-not-triggered-for-interface-annotations
- https://stackoverflow.com/questions/7178782/aspectj-pointcut-for-methods-that-override-an-interface-method-with-an-annotati
According to the Java 5 specification, non-type annotations are not inherited, and annotations on types are only inherited if they have the @Inherited
meta-annotation.
It's seems that it's impossible in spring-aop
.
I tried the code without spring-aop
, only using aspectjweaver
1.7.4, and adding an aop.xml
in resources/META-INF
:
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>
<aspect name="com.xxx.MyAspect"/>
</aspects>
<weaver options="-verbose -showWeaveInfo -Xset:weaveJavaxPackages=true" />
</aspectj>
and adding JVM parameter:
-javaagent:xxx/aspectjweaver-1.7.4.jar
It works no matter the @MyAnnotation
is on the interface or class. And then in around(ProceedingJoinPoint pjp)
, I can get the @MyAnnotation
with the API of pjp, like this:
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Class<?> targetClass = pjp.getTarget().getClass();
Method method = targetClass.getDeclaredMethod(signature.getName(), signature.getMethod().getParameterTypes());
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
or
Class<?>[] interfaces = targetClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
Method method = targetClass.getDeclaredMethod(signature.getName(),
signature.getMethod().getParameterTypes());
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
}
So I think spring-aop
may also have way to solve this problem, since it's a common use case for users to add annotation on the method of interface.
Something in AopUtils#getMostSpecificMethod
, AspectJExpressionPointcut#getShadowMatch(Method targetMethod, Method originalMethod)
may be about, I'm not sure.
Could you please give some help?