diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java index 009ff490f96..707c98f2676 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java @@ -668,7 +668,8 @@ public class AdvisedSupport extends ProxyConfig implements Advised { @Override public boolean equals(@Nullable Object other) { - return (this == other || (other instanceof MethodCacheKey that && this.method == that.method)); + return (this == other || (other instanceof MethodCacheKey that && + (this.method == that.method || this.method.equals(that.method)))); } @Override diff --git a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreatorTests.java b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreatorTests.java index a9c723a04fa..d84df387d56 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreatorTests.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreatorTests.java @@ -43,15 +43,18 @@ class DefaultAdvisorAutoProxyCreatorTests { * @see StaticMethodMatcherPointcut#matches(Method, Class) */ @Test // gh-33915 - void staticMethodMatcherPointcutMatchesMethodIsInvokedAgainForActualMethodInvocation() { + void staticMethodMatcherPointcutMatchesMethodIsNotInvokedAgainForActualMethodInvocation() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( DemoBean.class, DemoPointcutAdvisor.class, DefaultAdvisorAutoProxyCreator.class); DemoPointcutAdvisor demoPointcutAdvisor = context.getBean(DemoPointcutAdvisor.class); DemoBean demoBean = context.getBean(DemoBean.class); assertThat(demoPointcutAdvisor.matchesInvocationCount).as("matches() invocations before").isEqualTo(2); + // Invoke multiple times to ensure additional invocations don't affect the outcome. assertThat(demoBean.sayHello()).isEqualTo("Advised: Hello!"); - assertThat(demoPointcutAdvisor.matchesInvocationCount).as("matches() invocations after").isEqualTo(3); + assertThat(demoBean.sayHello()).isEqualTo("Advised: Hello!"); + assertThat(demoBean.sayHello()).isEqualTo("Advised: Hello!"); + assertThat(demoPointcutAdvisor.matchesInvocationCount).as("matches() invocations after").isEqualTo(2); context.close(); } diff --git a/spring-tx/src/test/java/org/springframework/transaction/interceptor/BeanFactoryTransactionTests.java b/spring-tx/src/test/java/org/springframework/transaction/interceptor/BeanFactoryTransactionTests.java index 0fe3bef54a6..727369f4d75 100644 --- a/spring-tx/src/test/java/org/springframework/transaction/interceptor/BeanFactoryTransactionTests.java +++ b/spring-tx/src/test/java/org/springframework/transaction/interceptor/BeanFactoryTransactionTests.java @@ -139,10 +139,10 @@ class BeanFactoryTransactionTests { // Invokes: getAge() * 2 and setAge() * 1 --> 2 + 1 = 3 method invocations. assertGetsAreNotTransactional(testBean); - // The transaction pointcut is currently asked if it matches() for all method - // invocations, but we cannot assert it's equal to 3 since the pointcut may be - // optimized and only invoked once. - assertThat(txnPointcut.counter).as("txnPointcut").isGreaterThanOrEqualTo(1).isLessThanOrEqualTo(3); + // The matches(Method, Class) method of the static transaction pointcut should not + // have been invoked for the actual invocation of the getAge() and setAge() methods. + assertThat(txnPointcut.counter).as("txnPointcut").isZero(); + assertThat(preInterceptor.counter).as("preInterceptor").isEqualTo(3); assertThat(postInterceptor.counter).as("postInterceptor").isEqualTo(3); }