1
1
/*
2
- * Copyright 2002-2023 the original author or authors.
2
+ * Copyright 2002-2024 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
22
22
import java .util .ArrayList ;
23
23
import java .util .Arrays ;
24
24
import java .util .Collection ;
25
- import java .util .Collections ;
26
25
import java .util .List ;
27
26
import java .util .Map ;
28
27
import java .util .concurrent .ConcurrentHashMap ;
@@ -85,10 +84,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
85
84
private boolean preFiltered = false ;
86
85
87
86
/** The AdvisorChainFactory to use. */
88
- private AdvisorChainFactory advisorChainFactory ;
89
-
90
- /** Cache with Method as key and advisor chain List as value. */
91
- private transient Map <MethodCacheKey , List <Object >> methodCache ;
87
+ private AdvisorChainFactory advisorChainFactory = DefaultAdvisorChainFactory .INSTANCE ;
92
88
93
89
/**
94
90
* Interfaces to be implemented by the proxy. Held in List to keep the order
@@ -110,6 +106,14 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
110
106
*/
111
107
private List <Advisor > advisorKey = this .advisors ;
112
108
109
+ /** Cache with Method as key and advisor chain List as value. */
110
+ @ Nullable
111
+ private transient Map <MethodCacheKey , List <Object >> methodCache ;
112
+
113
+ /** Cache with shared interceptors which are not method-specific. */
114
+ @ Nullable
115
+ private transient volatile List <Object > cachedInterceptors ;
116
+
113
117
/**
114
118
* Optional field for {@link AopProxy} implementations to store metadata in.
115
119
* Used by {@link JdkDynamicAopProxy}.
@@ -124,28 +128,16 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
124
128
* No-arg constructor for use as a JavaBean.
125
129
*/
126
130
public AdvisedSupport () {
127
- this .advisorChainFactory = DefaultAdvisorChainFactory .INSTANCE ;
128
- this .methodCache = new ConcurrentHashMap <>(32 );
129
131
}
130
132
131
133
/**
132
134
* Create an {@code AdvisedSupport} instance with the given parameters.
133
135
* @param interfaces the proxied interfaces
134
136
*/
135
137
public AdvisedSupport (Class <?>... interfaces ) {
136
- this ();
137
138
setInterfaces (interfaces );
138
139
}
139
140
140
- /**
141
- * Internal constructor for {@link #getConfigurationOnlyCopy()}.
142
- * @since 6.0.10
143
- */
144
- private AdvisedSupport (AdvisorChainFactory advisorChainFactory , Map <MethodCacheKey , List <Object >> methodCache ) {
145
- this .advisorChainFactory = advisorChainFactory ;
146
- this .methodCache = methodCache ;
147
- }
148
-
149
141
150
142
/**
151
143
* Set the given object as target.
@@ -497,6 +489,18 @@ public int countAdvicesOfType(@Nullable Class<?> adviceClass) {
497
489
* @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
498
490
*/
499
491
public List <Object > getInterceptorsAndDynamicInterceptionAdvice (Method method , @ Nullable Class <?> targetClass ) {
492
+ if (this .methodCache == null ) {
493
+ // Shared cache since there are no method-specific advisors (see below).
494
+ List <Object > cachedInterceptors = this .cachedInterceptors ;
495
+ if (cachedInterceptors == null ) {
496
+ cachedInterceptors = this .advisorChainFactory .getInterceptorsAndDynamicInterceptionAdvice (
497
+ this , method , targetClass );
498
+ this .cachedInterceptors = cachedInterceptors ;
499
+ }
500
+ return cachedInterceptors ;
501
+ }
502
+
503
+ // Method-specific cache for method-specific pointcuts
500
504
return this .methodCache .computeIfAbsent (new MethodCacheKey (method ), k ->
501
505
this .advisorChainFactory .getInterceptorsAndDynamicInterceptionAdvice (this , method , targetClass ));
502
506
}
@@ -505,8 +509,18 @@ public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @
505
509
* Invoked when advice has changed.
506
510
*/
507
511
protected void adviceChanged () {
508
- this .methodCache .clear ();
512
+ this .methodCache = null ;
513
+ this .cachedInterceptors = null ;
509
514
this .proxyMetadataCache = null ;
515
+
516
+ // Initialize method cache if necessary; otherwise,
517
+ // cachedInterceptors is going to be shared (see above).
518
+ for (Advisor advisor : this .advisors ) {
519
+ if (advisor instanceof PointcutAdvisor ) {
520
+ this .methodCache = new ConcurrentHashMap <>();
521
+ break ;
522
+ }
523
+ }
510
524
}
511
525
512
526
/**
@@ -545,21 +559,28 @@ protected void copyConfigurationFrom(AdvisedSupport other, TargetSource targetSo
545
559
* replacing the {@link TargetSource}.
546
560
*/
547
561
AdvisedSupport getConfigurationOnlyCopy () {
548
- AdvisedSupport copy = new AdvisedSupport (this . advisorChainFactory , this . methodCache );
562
+ AdvisedSupport copy = new AdvisedSupport ();
549
563
copy .copyFrom (this );
550
564
copy .targetSource = EmptyTargetSource .forClass (getTargetClass (), getTargetSource ().isStatic ());
565
+ copy .preFiltered = this .preFiltered ;
566
+ copy .advisorChainFactory = this .advisorChainFactory ;
551
567
copy .interfaces = new ArrayList <>(this .interfaces );
552
568
copy .advisors = new ArrayList <>(this .advisors );
553
569
copy .advisorKey = new ArrayList <>(this .advisors .size ());
554
570
for (Advisor advisor : this .advisors ) {
555
571
copy .advisorKey .add (new AdvisorKeyEntry (advisor ));
556
572
}
573
+ copy .methodCache = this .methodCache ;
574
+ copy .cachedInterceptors = this .cachedInterceptors ;
575
+ copy .proxyMetadataCache = this .proxyMetadataCache ;
557
576
return copy ;
558
577
}
559
578
560
579
void reduceToAdvisorKey () {
561
580
this .advisors = this .advisorKey ;
562
- this .methodCache = Collections .emptyMap ();
581
+ this .methodCache = null ;
582
+ this .cachedInterceptors = null ;
583
+ this .proxyMetadataCache = null ;
563
584
}
564
585
565
586
Object getAdvisorKey () {
@@ -596,8 +617,8 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound
596
617
// Rely on default serialization; just initialize state after deserialization.
597
618
ois .defaultReadObject ();
598
619
599
- // Initialize transient fields .
600
- this . methodCache = new ConcurrentHashMap <>( 32 );
620
+ // Initialize method cache if necessary .
621
+ adviceChanged ( );
601
622
}
602
623
603
624
0 commit comments