-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Description
Christian Hersevoort opened SPR-14180 and commented
Somewhat related to my other issue: #18750 (It's a different way to solve the same problem)
The case is as follows:
Beans:
- MyParentBean
- MyChildBeanA implements MyChildBean
- MyChildBeanB implements MyChildBean
@Configuration
public class MyBeanConfiguration
{
@Bean
public MyParentBean myParentBean(MyChildBeanA childBeanA)
{
MyParentBean myParentBean = new MyParentBean();
myParentBean.setMyChild(childBeanA);
return myParentBean;
}
}
@Component
public class MyParentBean
{
private MyChildBean myChild;
@Inject
public void setMyChild(MyChildBean myChild)
{
this.myChild = myChild;
}
}
I expect the MyParentBean.myChild field to only be Injected by the @Configuration
, and not by both ConfigurationClassPostProcessor and the AutowiredAnnotationBeanPostProcessor.
Expected:
- ConfigurationClassPostProcessor calls MyBeanConfiguration
- MyParentBean is created and field/property myChild is set.
- myChild is marked as satisfied(Injected)
What happens:
- ConfigurationClassPostProcessor calls MyBeanConfiguration
- MyParentBean is created and field/property myChild is set.
- AutowiredAnnotationBeanPostProcessor tries to Inject myChild again, but fails and throws a NoUniqueBeanDefinitionException
Changing between field and property injection doesn't help either e.g:
@Component
public class MyParentBean
{
@Inject
private MyChildBean myChild;
}
Changing @Bean
to @Bean
(autowire = Autowire.NO) doesn't help either, e.g:
@Configuration
public class MyBeanConfiguration
{
@Bean(autowire = Autowire.NO)
public MyParentBean myParentBean(MyChildBeanA childBeanA)
{
MyParentBean myParentBean = new MyParentBean();
myParentBean.setMyChild(childBeanA);
return myParentBean;
}
}
Is this expected behavior? I expect org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#checkPropertySkipping to be true and skip injection.
If this is expected behavior: is there a way to prevent @Bean
to be injected again by the AutowiredAnnotationBeanPostProcessor?
Issue Links:
- Inconsistency between property Injection and setter Injection causes NoUniqueBeanDefinitionException [SPR-14179] #18750 Inconsistency between property Injection and setter Injection causes NoUniqueBeanDefinitionException
- Clarify @Bean(autowire=NO) [SPR-14282] #18854 Clarify
@Bean
(autowire=NO)
Activity
spring-projects-issues commentedon Apr 15, 2016
Juergen Hoeller commented
This would be great to have... if we could technically do it. Unfortunately, the body of a factory method is a black box to the framework; we have no idea what's being called there. For that reason, this currently doesn't work. I'd love to make that work though!
spring-projects-issues commentedon Apr 15, 2016
Christian Hersevoort commented
Thanks for your quick reply!
Does this also mean
@Bean
(autowire = Autowire.NO) is broken? Because (even) without solving the "black-box" issue of@Configuration
, the user can tell Spring the bean is "done" injecting with Autowire.NO.Or does Autowire.NO mean something else in Spring?
spring-projects-issues commentedon Apr 15, 2016
Juergen Hoeller commented
This "autowire mode" indicates convention-based autowiring, introspecting setter method signatures and autowiring them by name or by type. Unfortunately, this is completely independent from annotation-driven autowiring.
Autowire.NO
is actually the default on@Bean
, indicating no such convention-based autowiring to be performed. That said, I like the idea of a flag which allows for skipping annotation-driven injection. We could introduce a dedicated flag for that or simply repurposeAutowire.NO
as you implied.Note that these problems do not arise with constructor injection. Our general recommendation for
@Bean
methods interacting with annotated component classes is to favor constructor injection, with annotated constructors naturally ignored on instances returned from@Bean
methods.