Skip to content

Avoid redundant type inspection and contribution during repository AOT processing - #3519

Open
snuderl wants to merge 1 commit into
spring-projects:mainfrom
snuderl:aot-dedup-type-contribution
Open

Avoid redundant type inspection and contribution during repository AOT processing#3519
snuderl wants to merge 1 commit into
spring-projects:mainfrom
snuderl:aot-dedup-type-contribution

Conversation

@snuderl

@snuderl snuderl commented Jul 30, 2026

Copy link
Copy Markdown

Closes #3518.

Repository AOT processing walks the same domain type graph repeatedly, which makes SpringApplicationAotProcessor scale poorly with the number of repositories and the size of the domain model:

  • DefaultAotRepositoryContext.discoverTypes() scans the configured base packages for types carrying the store's identifying annotations and inspects all of them — for every repository.
  • TypeContributor.contribute(…) hands each resolved type to BindingReflectionHintsRegistrar individually. The registrar starts with a fresh seen set per call, so shared types are re-traversed once per resolved type.
  • TypeCollector.ReachableTypes uses a per-root inspection cache, re-inspecting types reachable from more than one root.

This PR addresses all three:

  • Base package scan results are cached across the repository contexts created by a RepositoryRegistrationAotProcessor.
  • Reachable type inspection shares one inspection cache across all roots of a ReachableTypes instance.
  • Resolved types are contributed in a single BindingReflectionHintsRegistrar pass, skipping types already contributed to the same RuntimeHints.

The generated reachability-metadata.json is unchanged. For a real application with 17 Mongo repositories over a Jackson-annotated protobuf domain model, SpringApplicationAotProcessor drops from 60s to 12s; for a synthetic application with 32 repositories, from 33.6s to 4.5s.

A standalone reproducer with scaling measurements is available at https://github.com/snuderl/spring-data-aot-repro.


  • You have read the Spring Data contribution guidelines.
  • You use the code formatters provided here and have them applied to your changes. Don’t submit any formatting related changes.
  • You submit test cases (unit or integration tests) that back your changes.
  • You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).

…T processing.

Repository AOT processing walked the same domain type graph once per repository and once per contributed type. `DefaultAotRepositoryContext.discoverTypes()` scanned the configured base packages for types carrying the store's identifying annotations and inspected all of them for every repository, and `TypeContributor.contribute(…)` handed each resolved type to `BindingReflectionHintsRegistrar` individually, which starts with a fresh `seen` set per call and therefore re-traverses shared types once per resolved type. `TypeCollector.ReachableTypes` additionally used a per-root inspection cache, re-inspecting types reachable from more than one root.

Base package scan results are now cached across the repository contexts created by a `RepositoryRegistrationAotProcessor`, reachable type inspection shares one inspection cache across all roots of a `ReachableTypes` instance, and resolved types are contributed in a single `BindingReflectionHintsRegistrar` pass while skipping types already contributed to the same `RuntimeHints`.

The generated `reachability-metadata.json` is unchanged. For an application with 17 Mongo repositories over a Jackson-annotated protobuf domain model, `SpringApplicationAotProcessor` drops from 60s to 12s; for a synthetic application with 32 repositories, from 33.6s to 4.5s.

Signed-off-by: Blaz Snuderl <blaz.snuderl@opensea.io>
Co-Authored-By: Blaz Snuderl <blaz.snuderl@opensea.io>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 30, 2026
@mp911de
mp911de force-pushed the main branch 3 times, most recently from bde036c to adb1c6d Compare August 4, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Repository AOT processing re-traverses the same type graph once per repository and once per resolved type (O(repositories × documents × closure))

3 participants