From 1760e7fac8393a4faa849e7842bc32a350dfa4fb Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Thu, 12 Sep 2024 13:20:38 -0600 Subject: [PATCH] Cache Annotation Lookups Closes gh-15799 --- .../SecurityAnnotationScanners.java | 19 +++++++++++++++---- .../UniqueSecurityAnnotationScanner.java | 19 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanners.java b/core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanners.java index aa031d1347..1efaf25174 100644 --- a/core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanners.java +++ b/core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanners.java @@ -19,7 +19,9 @@ package org.springframework.security.core.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Factory for creating {@link SecurityAnnotationScanner} instances. @@ -29,6 +31,12 @@ import java.util.List; */ public final class SecurityAnnotationScanners { + private static final Map, SecurityAnnotationScanner> uniqueScanners = new HashMap<>(); + + private static final Map, SecurityAnnotationScanner> uniqueTemplateScanners = new HashMap<>(); + + private static final Map>, SecurityAnnotationScanner> uniqueTypesScanners = new HashMap<>(); + private SecurityAnnotationScanners() { } @@ -40,7 +48,8 @@ public final class SecurityAnnotationScanners { * @return the default {@link SecurityAnnotationScanner} */ public static SecurityAnnotationScanner requireUnique(Class type) { - return new UniqueSecurityAnnotationScanner<>(type); + return (SecurityAnnotationScanner) uniqueScanners.computeIfAbsent(type, + (t) -> new UniqueSecurityAnnotationScanner<>(type)); } /** @@ -60,9 +69,10 @@ public final class SecurityAnnotationScanners { public static SecurityAnnotationScanner requireUnique(Class type, AnnotationTemplateExpressionDefaults templateDefaults) { if (templateDefaults == null) { - return new UniqueSecurityAnnotationScanner<>(type); + return requireUnique(type); } - return new ExpressionTemplateSecurityAnnotationScanner<>(type, templateDefaults); + return (SecurityAnnotationScanner) uniqueTemplateScanners.computeIfAbsent(type, + (t) -> new ExpressionTemplateSecurityAnnotationScanner<>(t, templateDefaults)); } /** @@ -75,7 +85,8 @@ public final class SecurityAnnotationScanners { public static SecurityAnnotationScanner requireUnique(List> types) { List> casted = new ArrayList<>(); types.forEach((type) -> casted.add((Class) type)); - return new UniqueSecurityAnnotationScanner<>(casted); + return (SecurityAnnotationScanner) uniqueTypesScanners.computeIfAbsent(types, + (t) -> new UniqueSecurityAnnotationScanner<>(casted)); } } diff --git a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java index e8579c28e1..248ad4611e 100644 --- a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java +++ b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java @@ -22,10 +22,13 @@ import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import org.springframework.core.MethodClassKey; import org.springframework.core.annotation.AnnotationConfigurationException; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; @@ -86,6 +89,10 @@ final class UniqueSecurityAnnotationScanner extends Abstra private final List> types; + private final Map> uniqueParameterAnnotationCache = new HashMap<>(); + + private final Map> uniqueMethodAnnotationCache = new HashMap<>(); + UniqueSecurityAnnotationScanner(Class type) { Assert.notNull(type, "type cannot be null"); this.types = List.of(type); @@ -99,12 +106,16 @@ final class UniqueSecurityAnnotationScanner extends Abstra @Override MergedAnnotation merge(AnnotatedElement element, Class targetClass) { if (element instanceof Parameter parameter) { - List> annotations = findDirectAnnotations(parameter); - return requireUnique(parameter, annotations); + return this.uniqueParameterAnnotationCache.computeIfAbsent(parameter, (p) -> { + List> annotations = findDirectAnnotations(p); + return requireUnique(p, annotations); + }); } if (element instanceof Method method) { - List> annotations = findMethodAnnotations(method, targetClass); - return requireUnique(method, annotations); + return this.uniqueMethodAnnotationCache.computeIfAbsent(new MethodClassKey(method, targetClass), (k) -> { + List> annotations = findMethodAnnotations(method, targetClass); + return requireUnique(method, annotations); + }); } throw new AnnotationConfigurationException("Unsupported element of type " + element.getClass()); }