Spring 的类型注入
先定义一个接口:
public interface Animal { }
|
对应的有一些实现类:
@Component public class Dog implements Animal { }
@Component("myCat") public class Cat implements Animal { }
|
我们用 Spring 比较常见的用类型注入和名称注入:
@Resource private Dog dog;
@Resource("myCat") private Cat myCat;
|
然后今天在公司看到同事使用观察者模式的时候,使用了另外一种注入方式,注入的是List<XXX>
:
@Resource private List<Animal> animalList;
|
这个时候注入的时候实现 Animal 这个接口的所有实现类
Spring 按类型自动注入Array、List、Set、Map
Spring 按类型不仅仅注入类本身的,而且还可以注入Array、List、Set 和 Map 。
@Resource private Animal[] animalArr;
@Resource private List<Animal> animalList;
@Resource private Set<Animal> animalSet;
@Resource private Map<String, Animal> animalMap;
|
我们写一个测试类看看:
@Autowired private void print() { System.out.println(Arrays.toString(animalArr)); System.out.println(animalList); System.out.println(animalSet); System.out.println(animalMap); }
|
发现输出:
[com.cuzz.spring.impl.Cat@58cd06cb, com.cuzz.spring.impl.Dog@3be8821f] [com.cuzz.spring.impl.Cat@58cd06cb, com.cuzz.spring.impl.Dog@3be8821f] [com.cuzz.spring.impl.Cat@58cd06cb, com.cuzz.spring.impl.Dog@3be8821f] {myCat=com.cuzz.spring.impl.Cat@58cd06cb, dog=com.cuzz.spring.impl.Dog@3be8821f}
|
当为数组和集合的时候会把所有接口的实现类放入其中,当为 Map 时,key 对应的是 Bean 的名称,value 对应Bean。
源码分析
先定位到这个方法org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
resolveDependency 方法中定位到根据类型查找依赖 doResolveDependency。
@Override @Nullable public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); if (result == null) { result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } }
|
doResolveDependency 封装了依赖查找的各种情况,我们主要看 resolveMultipleBeans 方法。
@Nullable public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try {
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; }
} }
|
最终调用resolveMultipleBeans方法
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class<?> type = descriptor.getDependencyType();
if (descriptor instanceof StreamDependencyDescriptor) { Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } Stream<Object> stream = matchingBeans.keySet().stream() .map(name -> descriptor.resolveCandidate(name, type, this)) .filter(bean -> !(bean instanceof NullBean)); if (((StreamDependencyDescriptor) descriptor).isOrdered()) { stream = stream.sorted(adaptOrderComparator(matchingBeans)); } return stream; } else if (type.isArray()) { Class<?> componentType = type.getComponentType(); ResolvableType resolvableType = descriptor.getResolvableType(); Class<?> resolvedArrayType = resolvableType.resolve(type); if (resolvedArrayType != type) { componentType = resolvableType.getComponentType().resolve(); } if (componentType == null) { return null; } Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType); if (result instanceof Object[]) { Comparator<Object> comparator = adaptDependencyComparator(matchingBeans); if (comparator != null) { Arrays.sort((Object[]) result, comparator); } } return result; } 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; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); Object result = converter.convertIfNecessary(matchingBeans.values(), type); if (result instanceof List) { if (((List<?>) result).size() > 1) { Comparator<Object> comparator = adaptDependencyComparator(matchingBeans); if (comparator != null) { ((List<?>) result).sort(comparator); } } } return result; } else if (Map.class == type) { ResolvableType mapType = descriptor.getResolvableType().asMap(); Class<?> keyType = mapType.resolveGeneric(0); if (String.class != keyType) { return null; } Class<?> valueType = mapType.resolveGeneric(1); if (valueType == null) { return null; } Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } return matchingBeans; } else { return null; } }
|
从源码发现,不仅仅可以注入数组、集合和Map,还可以注入 Stream。
总结
Spring按类型注入不仅仅注入简单的Bean,还可以注入一些数组、集合、Map 以及 Stream。
如果想进一步了解这一块可以看看这篇文章Spring IoC 依赖注入(三)resolveDependency