Skip to content

Avoid repeated superclass introspection in AnnotationUtils.findAnnotation [SPR-16730] #21271

Closed
@spring-projects-issues

Description

@spring-projects-issues

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:

Referenced from: commits d78e27f, 26652a6

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions