Skip to content

Commit 3c067e5

Browse files
committed
optimized AnnotationUtils findAnnotation performance for repeated search on same interfaces (SPR-7630)
1 parent 0f92482 commit 3c067e5

File tree

1 file changed

+34
-12
lines changed

1 file changed

+34
-12
lines changed

org.springframework.core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Arrays;
2222
import java.util.HashMap;
2323
import java.util.Map;
24+
import java.util.WeakHashMap;
2425

2526
import org.springframework.core.BridgeMethodResolver;
2627
import org.springframework.util.Assert;
@@ -50,6 +51,8 @@ public abstract class AnnotationUtils {
5051
/** The attribute name for annotations with a single element */
5152
static final String VALUE = "value";
5253

54+
private static final Map<Class, Boolean> annotatedInterfaceCache = new WeakHashMap<Class, Boolean>();
55+
5356

5457
/**
5558
* Get all {@link Annotation Annotations} from the supplied {@link Method}.
@@ -120,26 +123,45 @@ public static <A extends Annotation> A findAnnotation(Method method, Class<A> an
120123
private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class[] ifcs) {
121124
A annotation = null;
122125
for (Class<?> iface : ifcs) {
123-
Method equivalentMethod;
124-
try {
125-
equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
126-
annotation = getAnnotation(equivalentMethod, annotationType);
126+
if (isInterfaceWithAnnotatedMethods(iface)) {
127+
try {
128+
Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
129+
annotation = getAnnotation(equivalentMethod, annotationType);
130+
}
131+
catch (NoSuchMethodException ex) {
132+
// Skip this interface - it doesn't have the method...
133+
}
134+
if (annotation != null) {
135+
break;
136+
}
127137
}
128-
catch (NoSuchMethodException e) {
129-
// skip this interface - it doesn't have the method
138+
}
139+
return annotation;
140+
}
141+
142+
private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
143+
synchronized (annotatedInterfaceCache) {
144+
Boolean flag = annotatedInterfaceCache.get(iface);
145+
if (flag != null) {
146+
return flag;
130147
}
131-
if (annotation != null) {
132-
break;
148+
boolean found = false;
149+
for (Method ifcMethod : iface.getMethods()) {
150+
if (ifcMethod.getAnnotations().length > 0) {
151+
found = true;
152+
break;
153+
}
133154
}
155+
annotatedInterfaceCache.put(iface, found);
156+
return found;
134157
}
135-
return annotation;
136158
}
137159

138160
/**
139161
* Find a single {@link Annotation} of <code>annotationType</code> from the supplied {@link Class},
140-
* traversing its interfaces and super classes if no annotation can be found on the given class itself.
162+
* traversing its interfaces and superclasses if no annotation can be found on the given class itself.
141163
* <p>This method explicitly handles class-level annotations which are not declared as
142-
* {@link Inherited inherited} <i>as well as annotations on interfaces</i>.
164+
* {@link java.lang.annotation.Inherited inherited} <i>as well as annotations on interfaces</i>.
143165
* <p>The algorithm operates as follows: Searches for an annotation on the given class and returns
144166
* it if found. Else searches all interfaces that the given class declares, returning the annotation
145167
* from the first matching candidate, if any. Else proceeds with introspection of the superclass
@@ -171,7 +193,7 @@ public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> a
171193
}
172194
}
173195
Class<?> superClass = clazz.getSuperclass();
174-
if (superClass == null || superClass.equals(Object.class)) {
196+
if (superClass == null || superClass == Object.class) {
175197
return null;
176198
}
177199
return findAnnotation(superClass, annotationType);

0 commit comments

Comments
 (0)