我们知道,Spring在遇到类型为 List、Map 之类的属性时,会根据类型收集容器内的所有Bean然后进行注入:
@Service
public class MainServiceImpl implement MainService{
// 当装配对象类型为 List 时,会根据泛型收集容器内的所有bean,并注入
@Autowired
List<MainRepository> repository;
}
今天遇到一位大牛写的代码,写了这样一段自己注入自己类型的代码:
@Primary
@Service
public class MainServiceImpl implement MainService{
// 当装配对象类型为 List 时,会根据泛型收集容器内的所有bean,并注入
@Autowired
List<MainService> service;
}
从上面我们可以看到 MainServiceImpl
实现了 MainService
,然后在自动装配中又注入了 MainService
类型的对象.
实现了 MainService
接口的组件还有两个,分别是 Main1ServiceImpl
和 MainServiceImpl
,照上面的代码来理解的话,在自动装配完成后 List 中会包含三个组件:
也即 MainServiceImpl
中会出现自己依赖自己的情况。但实际实现过程中,List 中只有两个组件,分别是Main1ServiceImpl
和 Main2ServiceImpl
,并没有出现自己依赖自己的问题。仔细想来,应该是Spring为我们处理了这些情况,因此找来了源码做了一下分析。
入口在 BeanFactory
中,Spring在实例化 Bean 完成之后,需要为 Bean 注入组件,当注入类型为 List 类型的时候,会从容器中获取到所有符合条件的 组件,然后将自身引用剔除掉.
// DefaultListableBeanFactory#resolveMultipleBeans:1437
// 当发现类型为 Collection 类型时,获取泛型中的元素类型,并通过类型获取匹配bean
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
// 并通过类型获取匹配对象
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
在根据元素类型获取匹配对象的时候会进行是否自引用校验:
// DefaultListableBeanFactory#findAutowireCandidates:1569
for (String candidate : candidateNames) {
// 判断是否自引用校验,如果不是自引用校验的话加入对象
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
也就是Spring在进行自动注入的时候,如果发现自引用,会将自引用剔除掉.