When I saw the AOP source code, I found that the getAdvisorMethods
method in ReflectiveAspectJAdvisorFactory
introspects the methods of Object
, and I am confused about this.
The sample as follow,
@Aspect
@EnableAspectJAutoProxy
@Slf4j
public class AopConfig {
@Around("execution(* cn.hiboot.framework.research.spring.research.SimpleStart.*(..))")
public Object around(ProceedingJoinPoint p) throws Throwable {
log.info("proceed before");
Object obj = p.proceed();
log.info("proceed after);
return obj;
}
}
@Slf4j
@Import(AopConfig.class)
public class SimpleStart {
public SimpleStart() {
log.info("execute constructor");
}
public String test(){
return "test method return value";
}
}
@Test
public void research(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SimpleStart.class);
SimpleStart bean = context.getBean(SimpleStart.class);
bean.test();
}
When a superclass is Object
, it continues recursively, because in ReflectiveAspectJAdvisorFactory.adviceMethodFilter
the mf = ReflectionUtils.USER_DECLARED_METHODS.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null))
.
The source code position:
https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java#L369
Comment From: sbrannen
I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.
Comment From: sbrannen
With regard to the behavior of ReflectiveAspectJAdvisorFactory
, this is likely a regression introduced in c419ea7ba76596beb5d548f5cc922947ab524b9b due to the composition of two MethodFilter
implementations using .and(...)
.
I introduced that change, and I assume that I believed the Javadoc for ReflectionUtils.USER_DECLARED_METHODS
which is unfortunately incorrect.
The USER_DECLARED_METHODS
MethodFilter
in fact does not filter out methods declared on java.lang.Object
. Rather, the implementation of ReflectionUtils.doWithMethods(Class<?>, MethodCallback, MethodFilter)
performs that filtering. The catch is that the MethodFilter
instance must be the exact USER_DECLARED_METHODS
instance, and when filters are composed via .and(...)
that equality check (==
) will never be true.
I see two ways to address this issue.
- Revert the changes in c419ea7ba76596beb5d548f5cc922947ab524b9b.
- Modify
ReflectionUtils.USER_DECLARED_METHODS
so that it actually does what the Javadoc claims it does.
The latter can be achieved as follows.
public static final MethodFilter USER_DECLARED_METHODS =
(method -> !method.isBridge() && !method.isSynthetic() && (method.getDeclaringClass() != Object.class));