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.

  1. Revert the changes in c419ea7ba76596beb5d548f5cc922947ab524b9b.
  2. 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));