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.
@@ -112,12 +112,12 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
112112 private BeanFactory beanFactory ;
113113
114114 @ Nullable
115- private transient ClassLoader pointcutClassLoader ;
115+ private transient volatile ClassLoader pointcutClassLoader ;
116116
117117 @ Nullable
118- private transient PointcutExpression pointcutExpression ;
118+ private transient volatile PointcutExpression pointcutExpression ;
119119
120- private transient boolean pointcutParsingFailed = false ;
120+ private transient volatile boolean pointcutParsingFailed ;
121121
122122
123123 /**
@@ -197,11 +197,14 @@ private void checkExpression() {
197197 * Lazily build the underlying AspectJ pointcut expression.
198198 */
199199 private PointcutExpression obtainPointcutExpression () {
200- if (this .pointcutExpression == null ) {
201- this .pointcutClassLoader = determinePointcutClassLoader ();
202- this .pointcutExpression = buildPointcutExpression (this .pointcutClassLoader );
200+ PointcutExpression pointcutExpression = this .pointcutExpression ;
201+ if (pointcutExpression == null ) {
202+ ClassLoader pointcutClassLoader = determinePointcutClassLoader ();
203+ pointcutExpression = buildPointcutExpression (pointcutClassLoader );
204+ this .pointcutClassLoader = pointcutClassLoader ;
205+ this .pointcutExpression = pointcutExpression ;
203206 }
204- return this . pointcutExpression ;
207+ return pointcutExpression ;
205208 }
206209
207210 /**
@@ -467,40 +470,24 @@ private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
467470 }
468471
469472 private ShadowMatch getShadowMatch (Method targetMethod , Method originalMethod ) {
470- ShadowMatch shadowMatch = ShadowMatchUtils .getShadowMatch (this , targetMethod );
473+ ShadowMatchKey key = new ShadowMatchKey (this , targetMethod );
474+ ShadowMatch shadowMatch = ShadowMatchUtils .getShadowMatch (key );
471475 if (shadowMatch == null ) {
472- PointcutExpression fallbackExpression = null ;
473- Method methodToMatch = targetMethod ;
474- try {
475- try {
476- shadowMatch = obtainPointcutExpression ().matchesMethodExecution (methodToMatch );
477- }
478- catch (ReflectionWorldException ex ) {
479- // Failed to introspect target method, probably because it has been loaded
480- // in a special ClassLoader. Let's try the declaring ClassLoader instead...
481- try {
482- fallbackExpression = getFallbackPointcutExpression (methodToMatch .getDeclaringClass ());
483- if (fallbackExpression != null ) {
484- shadowMatch = fallbackExpression .matchesMethodExecution (methodToMatch );
485- }
486- }
487- catch (ReflectionWorldException ex2 ) {
488- fallbackExpression = null ;
489- }
476+ PointcutExpression pointcutExpression = obtainPointcutExpression ();
477+ synchronized (pointcutExpression ) {
478+ shadowMatch = ShadowMatchUtils .getShadowMatch (key );
479+ if (shadowMatch != null ) {
480+ return shadowMatch ;
490481 }
491- if (targetMethod != originalMethod && (shadowMatch == null ||
492- (Proxy .isProxyClass (targetMethod .getDeclaringClass ()) &&
493- (shadowMatch .neverMatches () || containsAnnotationPointcut ())))) {
494- // Fall back to the plain original method in case of no resolvable match or a
495- // negative match on a proxy class (which doesn't carry any annotations on its
496- // redeclared methods), as well as for annotation pointcuts.
497- methodToMatch = originalMethod ;
482+ PointcutExpression fallbackExpression = null ;
483+ Method methodToMatch = targetMethod ;
484+ try {
498485 try {
499- shadowMatch = obtainPointcutExpression () .matchesMethodExecution (methodToMatch );
486+ shadowMatch = pointcutExpression .matchesMethodExecution (methodToMatch );
500487 }
501488 catch (ReflectionWorldException ex ) {
502- // Could neither introspect the target class nor the proxy class ->
503- // let's try the original method 's declaring class before we give up ...
489+ // Failed to introspect target method, probably because it has been loaded
490+ // in a special ClassLoader. Let 's try the declaring ClassLoader instead ...
504491 try {
505492 fallbackExpression = getFallbackPointcutExpression (methodToMatch .getDeclaringClass ());
506493 if (fallbackExpression != null ) {
@@ -511,21 +498,45 @@ private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
511498 fallbackExpression = null ;
512499 }
513500 }
501+ if (targetMethod != originalMethod && (shadowMatch == null ||
502+ (Proxy .isProxyClass (targetMethod .getDeclaringClass ()) &&
503+ (shadowMatch .neverMatches () || containsAnnotationPointcut ())))) {
504+ // Fall back to the plain original method in case of no resolvable match or a
505+ // negative match on a proxy class (which doesn't carry any annotations on its
506+ // redeclared methods), as well as for annotation pointcuts.
507+ methodToMatch = originalMethod ;
508+ try {
509+ shadowMatch = pointcutExpression .matchesMethodExecution (methodToMatch );
510+ }
511+ catch (ReflectionWorldException ex ) {
512+ // Could neither introspect the target class nor the proxy class ->
513+ // let's try the original method's declaring class before we give up...
514+ try {
515+ fallbackExpression = getFallbackPointcutExpression (methodToMatch .getDeclaringClass ());
516+ if (fallbackExpression != null ) {
517+ shadowMatch = fallbackExpression .matchesMethodExecution (methodToMatch );
518+ }
519+ }
520+ catch (ReflectionWorldException ex2 ) {
521+ fallbackExpression = null ;
522+ }
523+ }
524+ }
514525 }
526+ catch (Throwable ex ) {
527+ // Possibly AspectJ 1.8.10 encountering an invalid signature
528+ logger .debug ("PointcutExpression matching rejected target method" , ex );
529+ fallbackExpression = null ;
530+ }
531+ if (shadowMatch == null ) {
532+ shadowMatch = new ShadowMatchImpl (org .aspectj .util .FuzzyBoolean .NO , null , null , null );
533+ }
534+ else if (shadowMatch .maybeMatches () && fallbackExpression != null ) {
535+ shadowMatch = new DefensiveShadowMatch (shadowMatch ,
536+ fallbackExpression .matchesMethodExecution (methodToMatch ));
537+ }
538+ shadowMatch = ShadowMatchUtils .setShadowMatch (key , shadowMatch );
515539 }
516- catch (Throwable ex ) {
517- // Possibly AspectJ 1.8.10 encountering an invalid signature
518- logger .debug ("PointcutExpression matching rejected target method" , ex );
519- fallbackExpression = null ;
520- }
521- if (shadowMatch == null ) {
522- shadowMatch = new ShadowMatchImpl (org .aspectj .util .FuzzyBoolean .NO , null , null , null );
523- }
524- else if (shadowMatch .maybeMatches () && fallbackExpression != null ) {
525- shadowMatch = new DefensiveShadowMatch (shadowMatch ,
526- fallbackExpression .matchesMethodExecution (methodToMatch ));
527- }
528- shadowMatch = ShadowMatchUtils .setShadowMatch (this , targetMethod , shadowMatch );
529540 }
530541 return shadowMatch ;
531542 }
@@ -720,4 +731,8 @@ public void setMatchingContext(MatchingContext aMatchContext) {
720731 }
721732 }
722733
734+
735+ private record ShadowMatchKey (AspectJExpressionPointcut expression , Method method ) {
736+ }
737+
723738}
0 commit comments