Cache Annotation Lookups

Closes gh-15799
This commit is contained in:
Josh Cummings 2024-09-12 13:20:38 -06:00
parent d194724a04
commit 1760e7fac8
2 changed files with 30 additions and 8 deletions

View File

@ -19,7 +19,9 @@ package org.springframework.security.core.annotation;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Factory for creating {@link SecurityAnnotationScanner} instances. * Factory for creating {@link SecurityAnnotationScanner} instances.
@ -29,6 +31,12 @@ import java.util.List;
*/ */
public final class SecurityAnnotationScanners { public final class SecurityAnnotationScanners {
private static final Map<Class<? extends Annotation>, SecurityAnnotationScanner<? extends Annotation>> uniqueScanners = new HashMap<>();
private static final Map<Class<? extends Annotation>, SecurityAnnotationScanner<? extends Annotation>> uniqueTemplateScanners = new HashMap<>();
private static final Map<List<Class<? extends Annotation>>, SecurityAnnotationScanner<? extends Annotation>> uniqueTypesScanners = new HashMap<>();
private SecurityAnnotationScanners() { private SecurityAnnotationScanners() {
} }
@ -40,7 +48,8 @@ public final class SecurityAnnotationScanners {
* @return the default {@link SecurityAnnotationScanner} * @return the default {@link SecurityAnnotationScanner}
*/ */
public static <A extends Annotation> SecurityAnnotationScanner<A> requireUnique(Class<A> type) { public static <A extends Annotation> SecurityAnnotationScanner<A> requireUnique(Class<A> type) {
return new UniqueSecurityAnnotationScanner<>(type); return (SecurityAnnotationScanner<A>) uniqueScanners.computeIfAbsent(type,
(t) -> new UniqueSecurityAnnotationScanner<>(type));
} }
/** /**
@ -60,9 +69,10 @@ public final class SecurityAnnotationScanners {
public static <A extends Annotation> SecurityAnnotationScanner<A> requireUnique(Class<A> type, public static <A extends Annotation> SecurityAnnotationScanner<A> requireUnique(Class<A> type,
AnnotationTemplateExpressionDefaults templateDefaults) { AnnotationTemplateExpressionDefaults templateDefaults) {
if (templateDefaults == null) { if (templateDefaults == null) {
return new UniqueSecurityAnnotationScanner<>(type); return requireUnique(type);
} }
return new ExpressionTemplateSecurityAnnotationScanner<>(type, templateDefaults); return (SecurityAnnotationScanner<A>) uniqueTemplateScanners.computeIfAbsent(type,
(t) -> new ExpressionTemplateSecurityAnnotationScanner<>(t, templateDefaults));
} }
/** /**
@ -75,7 +85,8 @@ public final class SecurityAnnotationScanners {
public static SecurityAnnotationScanner<Annotation> requireUnique(List<Class<? extends Annotation>> types) { public static SecurityAnnotationScanner<Annotation> requireUnique(List<Class<? extends Annotation>> types) {
List<Class<Annotation>> casted = new ArrayList<>(); List<Class<Annotation>> casted = new ArrayList<>();
types.forEach((type) -> casted.add((Class<Annotation>) type)); types.forEach((type) -> casted.add((Class<Annotation>) type));
return new UniqueSecurityAnnotationScanner<>(casted); return (SecurityAnnotationScanner<Annotation>) uniqueTypesScanners.computeIfAbsent(types,
(t) -> new UniqueSecurityAnnotationScanner<>(casted));
} }
} }

View File

@ -22,10 +22,13 @@ import java.lang.reflect.Method;
import java.lang.reflect.Parameter; import java.lang.reflect.Parameter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.springframework.core.MethodClassKey;
import org.springframework.core.annotation.AnnotationConfigurationException; import org.springframework.core.annotation.AnnotationConfigurationException;
import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations;
@ -86,6 +89,10 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
private final List<Class<A>> types; private final List<Class<A>> types;
private final Map<Parameter, MergedAnnotation<A>> uniqueParameterAnnotationCache = new HashMap<>();
private final Map<MethodClassKey, MergedAnnotation<A>> uniqueMethodAnnotationCache = new HashMap<>();
UniqueSecurityAnnotationScanner(Class<A> type) { UniqueSecurityAnnotationScanner(Class<A> type) {
Assert.notNull(type, "type cannot be null"); Assert.notNull(type, "type cannot be null");
this.types = List.of(type); this.types = List.of(type);
@ -99,12 +106,16 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
@Override @Override
MergedAnnotation<A> merge(AnnotatedElement element, Class<?> targetClass) { MergedAnnotation<A> merge(AnnotatedElement element, Class<?> targetClass) {
if (element instanceof Parameter parameter) { if (element instanceof Parameter parameter) {
List<MergedAnnotation<A>> annotations = findDirectAnnotations(parameter); return this.uniqueParameterAnnotationCache.computeIfAbsent(parameter, (p) -> {
return requireUnique(parameter, annotations); List<MergedAnnotation<A>> annotations = findDirectAnnotations(p);
return requireUnique(p, annotations);
});
} }
if (element instanceof Method method) { if (element instanceof Method method) {
return this.uniqueMethodAnnotationCache.computeIfAbsent(new MethodClassKey(method, targetClass), (k) -> {
List<MergedAnnotation<A>> annotations = findMethodAnnotations(method, targetClass); List<MergedAnnotation<A>> annotations = findMethodAnnotations(method, targetClass);
return requireUnique(method, annotations); return requireUnique(method, annotations);
});
} }
throw new AnnotationConfigurationException("Unsupported element of type " + element.getClass()); throw new AnnotationConfigurationException("Unsupported element of type " + element.getClass());
} }