Skip to content

Apply InstanceSupplier post-processing when bypassed by explicit args#36462

Open
vlsi wants to merge 1 commit intospring-projects:mainfrom
vlsi:fix/gh-35871-prototype-aot-autowired-setter
Open

Apply InstanceSupplier post-processing when bypassed by explicit args#36462
vlsi wants to merge 1 commit intospring-projects:mainfrom
vlsi:fix/gh-35871-prototype-aot-autowired-setter

Conversation

@vlsi
Copy link
Contributor

@vlsi vlsi commented Mar 13, 2026

Summary

Fixes #35871.

When a bean definition has an InstanceSupplier with andThen() post-processing (as generated by AOT for @Autowired setter injection), calling getBean(name, args) bypasses the InstanceSupplier in createBeanInstance() but the andThen() post-processing was silently skipped. This meant that @Autowired setter injection would not be invoked for prototype beans retrieved with explicit constructor arguments in AOT mode.

This PR introduces InstanceSupplier#postProcessInstance() — a method that applies only the post-processing chain (registered via andThen()) to an already-created instance, without invoking the instance creation itself. AbstractAutowireCapableBeanFactory#doCreateBean() now calls this when it detects that the instance supplier was bypassed due to explicit args.

Changed files

  • InstanceSupplier — new postProcessInstance(RegisteredBean, T) default method; the anonymous class returned by andThen() overrides it to chain through the after function.
  • AbstractAutowireCapableBeanFactory — new hook applyInstanceSupplierPostProcessing() (no-op by default), called in doCreateBean() when args != null and an InstanceSupplier is present.
  • DefaultListableBeanFactory — overrides applyInstanceSupplierPostProcessing() to delegate to InstanceSupplier#postProcessInstance().

Note for reviewers

The post-processing runs after addSingletonFactory() (early singleton caching). For the typical case where postProcessInstance() returns the same instance (e.g. setter injection), this is safe. If a custom andThen() returns a different object (wrapping), the existing circular reference detection at the end of doCreateBean() will detect the identity mismatch and throw BeanCurrentlyInCreationException — consistent with how Spring handles any BeanPostProcessor that changes bean identity. Reviewers may want to evaluate whether moving the post-processing before addSingletonFactory() would be preferable for the wrapping case, though that would diverge from the established pattern for other post-processors.

Test plan

  • PrototypeWithArgsAotTests — end-to-end AOT test: prototype bean with @Autowired setter + BeanFactoryAware, retrieved via getBean(name, args) in a fresh AOT-compiled context
  • DefaultListableBeanFactoryTests#singletonWithInstanceSupplierAndThenPostProcessingAppliedWithExplicitArgs — singleton bean with InstanceSupplier.andThen() + explicit args
  • DefaultListableBeanFactoryTests#prototypeWithInstanceSupplierAndThenPostProcessingAppliedWithExplicitArgs
    — prototype bean with InstanceSupplier.andThen() + explicit args

🤖 Generated with Claude Code (Opus 4.6)
🤖 Cross-reviewed with Codex (GPT 5.4)

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 13, 2026
@vlsi vlsi force-pushed the fix/gh-35871-prototype-aot-autowired-setter branch 3 times, most recently from 2eb20d9 to ecff60c Compare March 16, 2026 11:44
When getBean(name, args) is called with explicit constructor arguments,
the InstanceSupplier is intentionally bypassed (spring-projectsgh-32657). However, in
AOT mode, @Autowired setter/field injection is baked into the
InstanceSupplier's andThen() chain and AutowiredAnnotationBeanPostProcessor
is excluded from runtime registration. This means the autowiring
post-processing is lost when the supplier is bypassed.

Add InstanceSupplier.postProcessInstance() to allow applying only the
post-processing steps (from andThen()) to an already-created instance
without re-invoking creation. Call this from doCreateBean() when the
instance supplier was bypassed due to explicit args.

Closes spring-projectsgh-35871

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
@vlsi vlsi force-pushed the fix/gh-35871-prototype-aot-autowired-setter branch from ecff60c to a6099fa Compare March 16, 2026 14:10
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 or decided on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spring AOT processed application does not properly initialize Prototype Bean

2 participants