Skip to content

Share projection metadata read across factory instances - #3520

Open
zanarellidev wants to merge 1 commit into
spring-projects:mainfrom
zanarellidev:gh-3513-share-projection-metadata-cache
Open

Share projection metadata read across factory instances#3520
zanarellidev wants to merge 1 commit into
spring-projects:mainfrom
zanarellidev:gh-3513-share-projection-metadata-cache

Conversation

@zanarellidev

Copy link
Copy Markdown
  • 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. (No automated formatter goal is wired into mvn test/mvn package; matched the surrounding file's existing style by hand instead of running the IDE formatter directly.)
  • 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).

Closes #3513.

DefaultProjectionInformation.PropertyDescriptorSource.getMetadata() performed a fresh ASM
MetadataReader classpath read of a projection interface's .class file on every construction,
and ProxyProjectionFactory.projectionInformationCache is per-instance. Two independent
ProxyProjectionFactory/SpelAwareProxyProjectionFactory instances resolving the same projection
type each paid their own class-file read, with no sharing. In reactive applications this is the
blocking-I/O-on-event-loop Blockhound violation described in the issue.

This PR adds a shared, type-keyed ConcurrentReferenceHashMap (weak keys) cache for the metadata
read, below the per-factory layer, matching the approach the reporter proposed in #3513.

ProjectionMetadataCachingProbeTests reproduces the issue without needing R2DBC/Blockhound: it
uses a custom child-first ClassLoader that counts real .class resource reads, and confirms two
independent factory instances resolving the same projection type only trigger one read after this
fix (previously two).

DefaultProjectionInformation.PropertyDescriptorSource.getMetadata()
performed a fresh ASM MetadataReader classpath read of a projection
interface's class file on every construction, and
ProxyProjectionFactory.projectionInformationCache is per-instance.
Two independent ProxyProjectionFactory/SpelAwareProxyProjectionFactory
instances resolving the same projection type each paid their own
class file read, with no sharing. In reactive applications this shows
up as a Blockhound-flagged blocking file read on the event loop.

Add a shared, type-keyed ConcurrentReferenceHashMap (weak keys) cache
for the metadata read, below the per-factory layer.

Closes spring-projects#3513

Signed-off-by: zanarelli <zanarelli.dev@gmail.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 1, 2026
@mp911de mp911de self-assigned this Aug 3, 2026
@mp911de
mp911de force-pushed the main branch 4 times, most recently from adb1c6d to 0ba14c1 Compare August 5, 2026 14:13
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.

Projection computation is causing a blocking call with Blockhound in reactive applications

3 participants