Apply InstanceSupplier post-processing when bypassed by explicit args#36462
Open
vlsi wants to merge 2 commits intospring-projects:mainfrom
Open
Apply InstanceSupplier post-processing when bypassed by explicit args#36462vlsi wants to merge 2 commits intospring-projects:mainfrom
vlsi wants to merge 2 commits intospring-projects:mainfrom
Conversation
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>
…xplicit args Clarify that applyInstanceSupplierPostProcessing() can also run for singleton beans created via getBean(name, args), not only prototypes. The previous comment incorrectly stated this code path only applies to non-singleton beans. In practice, getBean(name, args) can create a singleton on first lookup since doGetBean only reuses the singleton cache when args == null. The ordering (post-processing after addSingletonFactory) is consistent with how Spring handles any BeanPostProcessor that changes bean identity: circular reference detection at the end of doCreateBean will detect the mismatch and throw BeanCurrentlyInCreationException. For the typical case where post-processing returns the same instance (e.g. setter injection), this is safe. Add two tests verifying InstanceSupplier.andThen() post-processing is applied when the instance supplier is bypassed due to explicit args, for both singleton and prototype scopes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
8d1244f to
294d050
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #35871.
When a bean definition has an
InstanceSupplierwithandThen()post-processing (as generated by AOT for@Autowiredsetter injection), callinggetBean(name, args)bypasses theInstanceSupplierincreateBeanInstance()but theandThen()post-processing was silently skipped. This meant that@Autowiredsetter 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 viaandThen()) 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— newpostProcessInstance(RegisteredBean, T)default method; the anonymous class returned byandThen()overrides it to chain through theafterfunction.AbstractAutowireCapableBeanFactory— new hookapplyInstanceSupplierPostProcessing()(no-op by default), called indoCreateBean()whenargs != nulland anInstanceSupplieris present.DefaultListableBeanFactory— overridesapplyInstanceSupplierPostProcessing()to delegate toInstanceSupplier#postProcessInstance().Note for reviewers
The post-processing runs after
addSingletonFactory()(early singleton caching). For the typical case wherepostProcessInstance()returns the same instance (e.g. setter injection), this is safe. If a customandThen()returns a different object (wrapping), the existing circular reference detection at the end ofdoCreateBean()will detect the identity mismatch and throwBeanCurrentlyInCreationException— consistent with how Spring handles anyBeanPostProcessorthat changes bean identity. Reviewers may want to evaluate whether moving the post-processing beforeaddSingletonFactory()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@Autowiredsetter +BeanFactoryAware, retrieved viagetBean(name, args)in a fresh AOT-compiled contextDefaultListableBeanFactoryTests#singletonWithInstanceSupplierAndThenPostProcessingAppliedWithExplicitArgs— singleton bean withInstanceSupplier.andThen()+ explicit argsDefaultListableBeanFactoryTests#prototypeWithInstanceSupplierAndThenPostProcessingAppliedWithExplicitArgs— prototype bean with
InstanceSupplier.andThen()+ explicit args🤖 Generated with Claude Code (Opus 4.6)
🤖 Cross-reviewed with Codex (GPT 5.4)