spring-context注解源码系列九——@Primary
注解说明
Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one ‘primary’ bean exists among the candidates, it will be the autowired value.
在spring根据类型进行注入或者寻找Bean的时候,如果存在多个可注入对象,即该类型有多个Bean的时候,被@Primary标记的Bean会成为最终被选择的那个,当然,如果这些对象里面有超过1个Bean被@Primary标记,则会抛出异常。
使用示例
@Component
public class FooService {
private FooRepository fooRepository;
@Autowired
public FooService(FooRepository fooRepository) {
// 被注入的对象是 HibernateFooRepository
this.fooRepository = fooRepository;
}
}
@Component
public class JdbcFooRepository extends FooRepository {
public JdbcFooRepository(DataSource dataSource) {
// ...
}
}
@Primary
@Component
public class HibernateFooRepository extends FooRepository {
public HibernateFooRepository(SessionFactory sessionFactory) {
// ...
}
}
相关源码
AnnotationConfigUtils
/**
* 解析beanDefinition的附加的一些通用注解
*/
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
......
// 如果存在@Primary,则设置BeanDefinition的primary属性
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
......
}
DefaultListableBeanFactory
/**
* Determine the primary candidate in the given set of beans.
* @param candidates a Map of candidate names and candidate instances
* (or candidate classes if not created yet) that match the required type
* @param requiredType the target dependency type to match against
* @return the name of the primary candidate, or {@code null} if none found
* @see #isPrimary(String, Object)
* 从候选列表里面找到的primary(主要)的那个bean
*/
@Nullable
protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String primaryBeanName = null;
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
// 根据BeanName判断是否是primary(主要的)
if (isPrimary(candidateBeanName, beanInstance)) {
if (primaryBeanName != null) {
// 如果当前已经存在一个primaryBean的情况,又找到了一个新的,
// 则根据2个Bean是否是本地的(当前bean工厂是否包含对应的beanName)来进一步判断
// 如果2个都是本地的,则直接保异常
// 如果新的那个1个是本地的,1个不是,则保留本地那个
// 如果2个都不是,则保持不变
boolean candidateLocal = containsBeanDefinition(candidateBeanName);
boolean primaryLocal = containsBeanDefinition(primaryBeanName);
if (candidateLocal && primaryLocal) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"more than one 'primary' bean found among candidates: " + candidates.keySet());
}
else if (candidateLocal) {
primaryBeanName = candidateBeanName;
}
}
else {
primaryBeanName = candidateBeanName;
}
}
}
return primaryBeanName;
}
/**
* Return whether the bean definition for the given bean name has been
* marked as a primary bean.
* @param beanName the name of the bean
* @param beanInstance the corresponding bean instance (can be null)
* @return whether the given bean qualifies as primary
* 根据给定的BeanName判断一个Bean是否是一个主要的Bean
*/
protected boolean isPrimary(String beanName, Object beanInstance) {
// 如果当前存在BeanName对应的BeanDefinition,则根据合并后的BeanDefinition判断是否是主要的
if (containsBeanDefinition(beanName)) {
return getMergedLocalBeanDefinition(beanName).isPrimary();
}
// 如果当前不存在,则从父工厂寻找并判断
BeanFactory parent = getParentBeanFactory();
return (parent instanceof DefaultListableBeanFactory &&
((DefaultListableBeanFactory) parent).isPrimary(beanName, beanInstance));
}