Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-16730

Avoid repeated superclass introspection in AnnotationUtils.findAnnotation

    XMLWordPrintable

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Minor
    • Resolution: Complete
    • Affects Version/s: 4.3.10
    • Fix Version/s: 5.0.6, 5.1 RC1
    • Component/s: Core
    • Labels:
      None
    • Last commented by a User:
      true

      Description

      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.

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              juergen.hoeller Juergen Hoeller
              Reporter:
              marc.boudreault Marc Boudreault
              Last updater:
              Spring Issues Spring Issues
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:
                Days since last comment:
                3 years, 30 weeks, 2 days ago