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.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<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() {
}
@ -40,7 +48,8 @@ public final class SecurityAnnotationScanners {
* @return the default {@link SecurityAnnotationScanner}
*/
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,
AnnotationTemplateExpressionDefaults templateDefaults) {
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) {
List<Class<Annotation>> casted = new ArrayList<>();
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.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<A extends Annotation> extends Abstra
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) {
Assert.notNull(type, "type cannot be null");
this.types = List.of(type);
@ -99,12 +106,16 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
@Override
MergedAnnotation<A> merge(AnnotatedElement element, Class<?> targetClass) {
if (element instanceof Parameter parameter) {
List<MergedAnnotation<A>> annotations = findDirectAnnotations(parameter);
return requireUnique(parameter, annotations);
return this.uniqueParameterAnnotationCache.computeIfAbsent(parameter, (p) -> {
List<MergedAnnotation<A>> annotations = findDirectAnnotations(p);
return requireUnique(p, annotations);
});
}
if (element instanceof Method method) {
List<MergedAnnotation<A>> annotations = findMethodAnnotations(method, targetClass);
return requireUnique(method, annotations);
return this.uniqueMethodAnnotationCache.computeIfAbsent(new MethodClassKey(method, targetClass), (k) -> {
List<MergedAnnotation<A>> annotations = findMethodAnnotations(method, targetClass);
return requireUnique(method, annotations);
});
}
throw new AnnotationConfigurationException("Unsupported element of type " + element.getClass());
}