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

Performance regression on startup (in particular in AnnotationUtils)

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Complete
    • Affects Version/s: 4.2.2
    • Fix Version/s: 4.2.3
    • Component/s: Core
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      There is a major performance regression on annotations lookup in Spring Framework 4.2. We found out that a basic Spring Boot application was 10% slower between 1.2 and 1.3. We did some investigation and found out that a Spring boot 1.3 app based on 4.2 was also 10% slower than the same app on 4.1

      One of the major hotspot difference is AnnotationUtils.findAnnotation. On 4.1 its own time is 23 ms (232ms in total) while on 4.2 it is 1,936ms (5,340ms in total)

        Activity

        Hide
        juergen.hoeller Juergen Hoeller added a comment -

        Based on my attempts today, a particularly wasteful part seems to be the synthesize step for annotations on re-retrieval: While we have been caching the original annotation result, we always re-synthesize the entire annotation for every lookup call... I've modified this to cache the synthesized result now which should provide a significant boost for re-retrieval attempts. However, I have no idea how much of a difference this makes in actual Boot startup time, so please re-run the tests there, Stéphane Nicoll...

        If this doesn't provide enough benefit yet, we could also try to skip the synthesize step altogether for lookup attempts where it doesn't make an actual difference, i.e. where the calling code is ok with aliased attributes to be exposed independently (which it may signal through a boolean flag). However, let's see where the change above takes us first.

        Juergen

        Show
        juergen.hoeller Juergen Hoeller added a comment - Based on my attempts today, a particularly wasteful part seems to be the synthesize step for annotations on re-retrieval: While we have been caching the original annotation result, we always re-synthesize the entire annotation for every lookup call... I've modified this to cache the synthesized result now which should provide a significant boost for re-retrieval attempts. However, I have no idea how much of a difference this makes in actual Boot startup time, so please re-run the tests there, Stéphane Nicoll ... If this doesn't provide enough benefit yet, we could also try to skip the synthesize step altogether for lookup attempts where it doesn't make an actual difference, i.e. where the calling code is ok with aliased attributes to be exposed independently (which it may signal through a boolean flag). However, let's see where the change above takes us first. Juergen
        Hide
        juergen.hoeller Juergen Hoeller added a comment -

        A few further steps taken in the meantime:

        We're avoiding our rather expensive annotation retrieval algorithm in common callers of AnnotatedElementUtils when there are no annotations to begin with: e.g. in StandardAnnotationMetadata, AutowiredAnnotationBeanPostProcessor, AnnotationTransactionAttributeSource. StandardAnnotationMetadata also caches the annotation array now, avoiding repeated re-retrieval.

        AnnotatedElementUtils consistently operates on the actual annotation type if available, avoiding String name comparisons in favor of annotation type identity checks wherever possible. Also, it avoids double getDeclaredAnnotations/getAnnotations checks on anything other than Classes now - since they'll always deliver the same result for Methods etc anyway, just in a wasteful fresh array.

        I've also fixed our new 4.2 order determination check in ConfigurationClassUtils so that it only kicks in for actual configuration candidates; it was running through an unnecessary Order annotation lookup for every single bean in the context before.

        Juergen

        Show
        juergen.hoeller Juergen Hoeller added a comment - A few further steps taken in the meantime: We're avoiding our rather expensive annotation retrieval algorithm in common callers of AnnotatedElementUtils when there are no annotations to begin with: e.g. in StandardAnnotationMetadata, AutowiredAnnotationBeanPostProcessor, AnnotationTransactionAttributeSource. StandardAnnotationMetadata also caches the annotation array now, avoiding repeated re-retrieval. AnnotatedElementUtils consistently operates on the actual annotation type if available, avoiding String name comparisons in favor of annotation type identity checks wherever possible. Also, it avoids double getDeclaredAnnotations/getAnnotations checks on anything other than Classes now - since they'll always deliver the same result for Methods etc anyway, just in a wasteful fresh array. I've also fixed our new 4.2 order determination check in ConfigurationClassUtils so that it only kicks in for actual configuration candidates; it was running through an unnecessary Order annotation lookup for every single bean in the context before. Juergen
        Hide
        juergen.hoeller Juergen Hoeller added a comment -

        As a further step, we're avoiding annotation synthesizing for getAnnotationAttributes retrieval now, in particular affecting ASM-based introspection during component scans.

        Show
        juergen.hoeller Juergen Hoeller added a comment - As a further step, we're avoiding annotation synthesizing for getAnnotationAttributes retrieval now, in particular affecting ASM-based introspection during component scans.

          People

          • Assignee:
            juergen.hoeller Juergen Hoeller
            Reporter:
            snicoll Stéphane Nicoll
            Last updater:
            Stéphane Nicoll
          • Votes:
            1 Vote for this issue
            Watchers:
            10 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:
              Days since last comment:
              2 years, 16 weeks, 2 days ago