11/*
2- * Copyright 2002-2024 the original author or authors.
2+ * Copyright 2002-2025 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
@@ -109,11 +109,11 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
109109
110110 private @ Nullable BeanFactory beanFactory ;
111111
112- private transient @ Nullable ClassLoader pointcutClassLoader ;
112+ private transient volatile @ Nullable ClassLoader pointcutClassLoader ;
113113
114- private transient @ Nullable PointcutExpression pointcutExpression ;
114+ private transient volatile @ Nullable PointcutExpression pointcutExpression ;
115115
116- private transient boolean pointcutParsingFailed = false ;
116+ private transient volatile boolean pointcutParsingFailed ;
117117
118118
119119 /**
@@ -193,11 +193,14 @@ private void checkExpression() {
193193 * Lazily build the underlying AspectJ pointcut expression.
194194 */
195195 private PointcutExpression obtainPointcutExpression () {
196- if (this .pointcutExpression == null ) {
197- this .pointcutClassLoader = determinePointcutClassLoader ();
198- this .pointcutExpression = buildPointcutExpression (this .pointcutClassLoader );
196+ PointcutExpression pointcutExpression = this .pointcutExpression ;
197+ if (pointcutExpression == null ) {
198+ ClassLoader pointcutClassLoader = determinePointcutClassLoader ();
199+ pointcutExpression = buildPointcutExpression (pointcutClassLoader );
200+ this .pointcutClassLoader = pointcutClassLoader ;
201+ this .pointcutExpression = pointcutExpression ;
199202 }
200- return this . pointcutExpression ;
203+ return pointcutExpression ;
201204 }
202205
203206 /**
@@ -460,40 +463,24 @@ private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
460463 }
461464
462465 private ShadowMatch getShadowMatch (Method targetMethod , Method originalMethod ) {
463- ShadowMatch shadowMatch = ShadowMatchUtils .getShadowMatch (this , targetMethod );
466+ ShadowMatchKey key = new ShadowMatchKey (this , targetMethod );
467+ ShadowMatch shadowMatch = ShadowMatchUtils .getShadowMatch (key );
464468 if (shadowMatch == null ) {
465- PointcutExpression fallbackExpression = null ;
466- Method methodToMatch = targetMethod ;
467- try {
468- try {
469- shadowMatch = obtainPointcutExpression ().matchesMethodExecution (methodToMatch );
470- }
471- catch (ReflectionWorldException ex ) {
472- // Failed to introspect target method, probably because it has been loaded
473- // in a special ClassLoader. Let's try the declaring ClassLoader instead...
474- try {
475- fallbackExpression = getFallbackPointcutExpression (methodToMatch .getDeclaringClass ());
476- if (fallbackExpression != null ) {
477- shadowMatch = fallbackExpression .matchesMethodExecution (methodToMatch );
478- }
479- }
480- catch (ReflectionWorldException ex2 ) {
481- fallbackExpression = null ;
482- }
469+ PointcutExpression pointcutExpression = obtainPointcutExpression ();
470+ synchronized (pointcutExpression ) {
471+ shadowMatch = ShadowMatchUtils .getShadowMatch (key );
472+ if (shadowMatch != null ) {
473+ return shadowMatch ;
483474 }
484- if (targetMethod != originalMethod && (shadowMatch == null ||
485- (Proxy .isProxyClass (targetMethod .getDeclaringClass ()) &&
486- (shadowMatch .neverMatches () || containsAnnotationPointcut ())))) {
487- // Fall back to the plain original method in case of no resolvable match or a
488- // negative match on a proxy class (which doesn't carry any annotations on its
489- // redeclared methods), as well as for annotation pointcuts.
490- methodToMatch = originalMethod ;
475+ PointcutExpression fallbackExpression = null ;
476+ Method methodToMatch = targetMethod ;
477+ try {
491478 try {
492- shadowMatch = obtainPointcutExpression () .matchesMethodExecution (methodToMatch );
479+ shadowMatch = pointcutExpression .matchesMethodExecution (methodToMatch );
493480 }
494481 catch (ReflectionWorldException ex ) {
495- // Could neither introspect the target class nor the proxy class ->
496- // let's try the original method 's declaring class before we give up ...
482+ // Failed to introspect target method, probably because it has been loaded
483+ // in a special ClassLoader. Let 's try the declaring ClassLoader instead ...
497484 try {
498485 fallbackExpression = getFallbackPointcutExpression (methodToMatch .getDeclaringClass ());
499486 if (fallbackExpression != null ) {
@@ -504,21 +491,45 @@ private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
504491 fallbackExpression = null ;
505492 }
506493 }
494+ if (targetMethod != originalMethod && (shadowMatch == null ||
495+ (Proxy .isProxyClass (targetMethod .getDeclaringClass ()) &&
496+ (shadowMatch .neverMatches () || containsAnnotationPointcut ())))) {
497+ // Fall back to the plain original method in case of no resolvable match or a
498+ // negative match on a proxy class (which doesn't carry any annotations on its
499+ // redeclared methods), as well as for annotation pointcuts.
500+ methodToMatch = originalMethod ;
501+ try {
502+ shadowMatch = pointcutExpression .matchesMethodExecution (methodToMatch );
503+ }
504+ catch (ReflectionWorldException ex ) {
505+ // Could neither introspect the target class nor the proxy class ->
506+ // let's try the original method's declaring class before we give up...
507+ try {
508+ fallbackExpression = getFallbackPointcutExpression (methodToMatch .getDeclaringClass ());
509+ if (fallbackExpression != null ) {
510+ shadowMatch = fallbackExpression .matchesMethodExecution (methodToMatch );
511+ }
512+ }
513+ catch (ReflectionWorldException ex2 ) {
514+ fallbackExpression = null ;
515+ }
516+ }
517+ }
507518 }
519+ catch (Throwable ex ) {
520+ // Possibly AspectJ 1.8.10 encountering an invalid signature
521+ logger .debug ("PointcutExpression matching rejected target method" , ex );
522+ fallbackExpression = null ;
523+ }
524+ if (shadowMatch == null ) {
525+ shadowMatch = new ShadowMatchImpl (org .aspectj .util .FuzzyBoolean .NO , null , null , null );
526+ }
527+ else if (shadowMatch .maybeMatches () && fallbackExpression != null ) {
528+ shadowMatch = new DefensiveShadowMatch (shadowMatch ,
529+ fallbackExpression .matchesMethodExecution (methodToMatch ));
530+ }
531+ shadowMatch = ShadowMatchUtils .setShadowMatch (key , shadowMatch );
508532 }
509- catch (Throwable ex ) {
510- // Possibly AspectJ 1.8.10 encountering an invalid signature
511- logger .debug ("PointcutExpression matching rejected target method" , ex );
512- fallbackExpression = null ;
513- }
514- if (shadowMatch == null ) {
515- shadowMatch = new ShadowMatchImpl (org .aspectj .util .FuzzyBoolean .NO , null , null , null );
516- }
517- else if (shadowMatch .maybeMatches () && fallbackExpression != null ) {
518- shadowMatch = new DefensiveShadowMatch (shadowMatch ,
519- fallbackExpression .matchesMethodExecution (methodToMatch ));
520- }
521- shadowMatch = ShadowMatchUtils .setShadowMatch (this , targetMethod , shadowMatch );
522533 }
523534 return shadowMatch ;
524535 }
@@ -713,4 +724,8 @@ public void setMatchingContext(MatchingContext aMatchContext) {
713724 }
714725 }
715726
727+
728+ private record ShadowMatchKey (AspectJExpressionPointcut expression , Method method ) {
729+ }
730+
716731}
0 commit comments