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