Skip to content

Commit 1760e7f

Browse files
committed
Cache Annotation Lookups
Closes gh-15799
1 parent d194724 commit 1760e7f

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanners.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import java.lang.annotation.Annotation;
2020
import java.lang.reflect.AnnotatedElement;
2121
import java.util.ArrayList;
22+
import java.util.HashMap;
2223
import java.util.List;
24+
import java.util.Map;
2325

2426
/**
2527
* Factory for creating {@link SecurityAnnotationScanner} instances.
@@ -29,6 +31,12 @@
2931
*/
3032
public final class SecurityAnnotationScanners {
3133

34+
private static final Map<Class<? extends Annotation>, SecurityAnnotationScanner<? extends Annotation>> uniqueScanners = new HashMap<>();
35+
36+
private static final Map<Class<? extends Annotation>, SecurityAnnotationScanner<? extends Annotation>> uniqueTemplateScanners = new HashMap<>();
37+
38+
private static final Map<List<Class<? extends Annotation>>, SecurityAnnotationScanner<? extends Annotation>> uniqueTypesScanners = new HashMap<>();
39+
3240
private SecurityAnnotationScanners() {
3341
}
3442

@@ -40,7 +48,8 @@ private SecurityAnnotationScanners() {
4048
* @return the default {@link SecurityAnnotationScanner}
4149
*/
4250
public static <A extends Annotation> SecurityAnnotationScanner<A> requireUnique(Class<A> type) {
43-
return new UniqueSecurityAnnotationScanner<>(type);
51+
return (SecurityAnnotationScanner<A>) uniqueScanners.computeIfAbsent(type,
52+
(t) -> new UniqueSecurityAnnotationScanner<>(type));
4453
}
4554

4655
/**
@@ -60,9 +69,10 @@ public static <A extends Annotation> SecurityAnnotationScanner<A> requireUnique(
6069
public static <A extends Annotation> SecurityAnnotationScanner<A> requireUnique(Class<A> type,
6170
AnnotationTemplateExpressionDefaults templateDefaults) {
6271
if (templateDefaults == null) {
63-
return new UniqueSecurityAnnotationScanner<>(type);
72+
return requireUnique(type);
6473
}
65-
return new ExpressionTemplateSecurityAnnotationScanner<>(type, templateDefaults);
74+
return (SecurityAnnotationScanner<A>) uniqueTemplateScanners.computeIfAbsent(type,
75+
(t) -> new ExpressionTemplateSecurityAnnotationScanner<>(t, templateDefaults));
6676
}
6777

6878
/**
@@ -75,7 +85,8 @@ public static <A extends Annotation> SecurityAnnotationScanner<A> requireUnique(
7585
public static SecurityAnnotationScanner<Annotation> requireUnique(List<Class<? extends Annotation>> types) {
7686
List<Class<Annotation>> casted = new ArrayList<>();
7787
types.forEach((type) -> casted.add((Class<Annotation>) type));
78-
return new UniqueSecurityAnnotationScanner<>(casted);
88+
return (SecurityAnnotationScanner<Annotation>) uniqueTypesScanners.computeIfAbsent(types,
89+
(t) -> new UniqueSecurityAnnotationScanner<>(casted));
7990
}
8091

8192
}

core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@
2222
import java.lang.reflect.Parameter;
2323
import java.util.ArrayList;
2424
import java.util.Collections;
25+
import java.util.HashMap;
2526
import java.util.HashSet;
2627
import java.util.List;
28+
import java.util.Map;
2729
import java.util.Set;
2830

31+
import org.springframework.core.MethodClassKey;
2932
import org.springframework.core.annotation.AnnotationConfigurationException;
3033
import org.springframework.core.annotation.MergedAnnotation;
3134
import org.springframework.core.annotation.MergedAnnotations;
@@ -86,6 +89,10 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
8689

8790
private final List<Class<A>> types;
8891

92+
private final Map<Parameter, MergedAnnotation<A>> uniqueParameterAnnotationCache = new HashMap<>();
93+
94+
private final Map<MethodClassKey, MergedAnnotation<A>> uniqueMethodAnnotationCache = new HashMap<>();
95+
8996
UniqueSecurityAnnotationScanner(Class<A> type) {
9097
Assert.notNull(type, "type cannot be null");
9198
this.types = List.of(type);
@@ -99,12 +106,16 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
99106
@Override
100107
MergedAnnotation<A> merge(AnnotatedElement element, Class<?> targetClass) {
101108
if (element instanceof Parameter parameter) {
102-
List<MergedAnnotation<A>> annotations = findDirectAnnotations(parameter);
103-
return requireUnique(parameter, annotations);
109+
return this.uniqueParameterAnnotationCache.computeIfAbsent(parameter, (p) -> {
110+
List<MergedAnnotation<A>> annotations = findDirectAnnotations(p);
111+
return requireUnique(p, annotations);
112+
});
104113
}
105114
if (element instanceof Method method) {
106-
List<MergedAnnotation<A>> annotations = findMethodAnnotations(method, targetClass);
107-
return requireUnique(method, annotations);
115+
return this.uniqueMethodAnnotationCache.computeIfAbsent(new MethodClassKey(method, targetClass), (k) -> {
116+
List<MergedAnnotation<A>> annotations = findMethodAnnotations(method, targetClass);
117+
return requireUnique(method, annotations);
118+
});
108119
}
109120
throw new AnnotationConfigurationException("Unsupported element of type " + element.getClass());
110121
}

0 commit comments

Comments
 (0)