Description
Chris Beams opened SPR-5529 and commented
In alignment with Java 5 style and migration of JavaConfig features into core, support the following signature on the BeanFactory interface:
<T> T getBean(Class<T> requiredType) throws BeansException;
This will need to be implemented by the following classes:
AbstractBeanFactory
SimpleJndiBeanFactory
StaticListableBeanFactory
AbstractApplicationContext
There are also several locations throughout the Spring test codebase that call getBean(null). These calls will have to be disambiguated as getBean((String)null).
With the above in mind, the addition of getBean(Class<T>) does introduce a minor backward compatibility issue for anyone calling getBean(null). Given that this is extremely unlikely (because it's meaningless to do so), it's probably not a significant concern.
Implementation approach:
Apply logic similar to that in getBeansOfType(), iterating through all beans, building up a collection of beans that match the given 'requiredType' parameter. If the resulting list contains exactly one bean, return it. If the list contains zero beans, throw a NoSuchBeanDefinitionException. If the list contains more than one matching bean, throw a BeansException specific to the issue. No suitable BeansException currently exists for this, so a suggestion would be 'AmbiguousBeanLookupException extends BeansException' with an appropriate error message, something to the effect of: "3 beans match requested type com.acme.Foo. Consider using getBean(String, Class<T>) to disambiguate. Matching bean names are: ['foo1', 'foo2', 'foo3']
Qualified access by type:
Currently we're supporting <T> T getBean(String, Class<T>). This is a qualification-by-bean-name scenario. We may also want to support qualification-by-@Qualifier
. Haven't given much thought to this, but something to the effect of:
<T> T getBean(Class<? extends Annotation> qualifier, Class<T> requiredType)
Such that a client can define two classes of the same supertype:
@Production
@Service
public XyzCustomerService implements CustomerService { ... }
@Testing
@Service
public TestCustomerService implements CustomerService { ... }
Where @Production
and @Testing
are both meta-annotated as @Qualifier
The user can then register bean definitions for both classes and access the production instance as follows:
ApplicationContext ctx = ...
CustomerService productionInstance = ctx.getBean(Production.class, CustomerService.class);
The latter portion of this issue may well be moved to an issue all its own. Just including it here for completeness & concision.
Issue Links:
- Support beanFactory.getBean(Bar.class) signature to instantiate a bean. [SPR-1956] #6649 Support beanFactory.getBean(Bar.class) signature to instantiate a bean. ("is duplicated by")
- Provide dedicated ApplicationContext implementations for use with (JavaConfig) @Configuration classes [SPR-5682] #10353 Provide dedicated ApplicationContext implementations for use with (JavaConfig)
@Configuration
classes