Closed
Description
Marc Boudreault opened SPR-16730 and commented
Hello,
We ran load tests and found that findAnnotation was one of the top method using CPU despite it uses caching.
We could correct this situation by caching NULL values with this simple change:
--- C:\Project\AnnotationUtils.java 2018-04-16 16:16:04.974657900 -0400
+++ C:\Project\src\main\java\org\springframework\core\annotation\AnnotationUtils.java 2018-03-12 16:58:54.540000000 -0400
@@ -136,6 +148,14 @@
new ConcurrentReferenceHashMap<Method, AliasDescriptor>(256);
private static transient Log logger;
+
+ private static final Annotation NULL_ANNOTATION = new Annotation() {
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ // TODO Auto-generated method stub
+ return null;
+ }};
/**
@@ -558,13 +578,14 @@
@SuppressWarnings("unchecked")
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
Assert.notNull(method, "Method must not be null");
+
if (annotationType == null) {
return null;
}
AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);
A result = (A) findAnnotationCache.get(cacheKey);
-
+
if (result == null) {
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType);
@@ -595,9 +616,13 @@
if (result != null) {
result = synthesizeAnnotation(result, method);
findAnnotationCache.put(cacheKey, result);
+ }else {
+ findAnnotationCache.put(cacheKey, NULL_ANNOTATION);
}
}
-
+ if(NULL_ANNOTATION == result) {
+ result = null;
+ }
return result;
}
@@ -691,8 +716,13 @@
if (result != null && synthesize) {
result = synthesizeAnnotation(result, clazz);
findAnnotationCache.put(cacheKey, result);
+ }else if(result == null && synthesize) {
+ findAnnotationCache.put(cacheKey, NULL_ANNOTATION);
}
}
+ if(NULL_ANNOTATION == result) {
+ result = null;
+ }
return result;
}
Often findAnnotation returns null - adding a key with NULL_ANNOTATION as the value resolved the issue. NULL_ANNOTATION is reverted to null prior returning.
After this change we observed an appreciable 4-5% performance improvement in our app across the board.
Affects: 4.3.10
Issue Links:
- ReflectionUtils slow down application startup on WebSphere [SPR-11882] #16501 ReflectionUtils slow down application startup on WebSphere
- Performance regression on startup (in particular in AnnotationUtils) [SPR-13621] #18199 Performance regression on startup (in particular in AnnotationUtils)
- Comprehensively cache annotated methods for interfaces and superclasses [SPR-16675] #21216 Comprehensively cache annotated methods for interfaces and superclasses
- Annotations on generic interface methods not found by AnnotationUtils [SPR-16060] #20609 Annotations on generic interface methods not found by AnnotationUtils
- Cache order result per Class in OrderUtils (for AnnotationAwareOrderComparator) [SPR-17064] #21602 Cache order result per Class in OrderUtils (for AnnotationAwareOrderComparator)
- Avoid unnecessary synthesizable annotation processing [SPR-16933] #21472 Avoid unnecessary synthesizable annotation processing