使用案例
案例一
假设现在有一个接口 MessageService
,这个接口有三个实现类 EmailService
,SmsService
,PushNotificationService
,那么可以通过 @Autowired
注解将这三个实现类对应的 Bean 注入到 NotificationManagerFieldInjection
这个 Bean 中。代码如下:
java
public interface MessageService {
}
@Component
public class EmailService implements MessageService {
}
@Component
public class SmsService implements MessageService {
}
@Component
public class PushNotificationService implements MessageService {
}
@Service
public class NotificationManagerFieldInjection {
@Autowired
private List<MessageService> messageServices;
}

案例二:
通过 @Order
注解指定 messageServices
中 Bean 的顺序:
java
public interface MessageService {
}
@Component
@Order(3)
public class EmailService implements MessageService {
}
@Component
@Order(2)
public class SmsService implements MessageService {
}
@Component
@Order(1)
public class PushNotificationService implements MessageService {
}
@Service
public class NotificationManagerFieldInjection {
@Autowired
private List<MessageService> messageServices;
}

那 Spring 中是如何实现将指定接口所有实现类对应的 Bean 都注入进来并实现排序的呢,接下来将从源码才层面进行分析。
实现原理
在前面的文章Spring 中@Autowired,@Resource,@Inject 注解实现原理 中介绍了实际上是在 DefaultListableBeanFactory
的 doResolveDependency()
方法中实现对象的解析的。那对于多个 Bean 的注入也同样是在这个方法里面完成的,在该方法里面的第四个分支就是负责处理这种情况的。代码如下:
java
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// Step 1: pre-resolved shortcut for single bean match, for example, from @Autowired
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
// Step 2: pre-defined value or expression, for example, from @Value
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
}
// Step 3: shortcut for declared dependency name or qualifier-suggested name matching target bean name
if (descriptor.usesStandardBeanLookup()) {
}
// Step 4a: multiple beans as stream / array / standard collection / plain map
// 这里负责处理多个Bean注入成steam,array,collection,map的情况
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
}
}
在 DefaultListableBeanFactory
中的 doResolveDependency()
方法中调用了 resolveMultipleBeans()
方法,在该方法中又会判断目标对象的类型是不是 Set
,List
,Map
中的一种,如果是的话,则会调用 resolveMultipleBeanCollection()
方法。代码如下:
java
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class<?> type = descriptor.getDependencyType();
if (descriptor instanceof StreamDependencyDescriptor streamDependencyDescriptor) {
// 省略代码
}
else if (type.isArray()) {
// 省略代码
}
else if (Collection.class == type || Set.class == type || List.class == type) {
return resolveMultipleBeanCollection(descriptor, beanName, autowiredBeanNames, typeConverter);
}
else if (Map.class == type) {
return resolveMultipleBeanMap(descriptor, beanName, autowiredBeanNames, typeConverter);
}
return null;
}
在 DefaultListableBeanFactory
的 resolveMultipleBeanCollection()
中,首先调用 findAutowireCandidates()
方法找到所有符合类型的 Bean,然后将它们转为目标对象类型,且如果目标对象类型是 List
类型,且获取到的 Comparator
不为空,则对结果进行排序。
java
private Object resolveMultipleBeanCollection(DependencyDescriptor descriptor,
@Nullable String beanName, @Nullable Set<String> autowiredBeanNames,
@Nullable TypeConverter typeConverter) {
Class<?> elementType =
descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
// 根据类型找到所有的Bean
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(),
descriptor.getDependencyType());
if (result instanceof List<?> list && list.size() > 1) {
// 按照comparator进行排序
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
list.sort(comparator);
}
}
return result;
}
Spring 默认提供了 AnnotationAwareOrderComparator
作为比较器,在它的 findOrderFromAnnotation()
方法中实现了查找顺序的逻辑,实际上会调用 OrderUtils
的 getOrderFromAnnotations()
方法。
java
private Integer findOrderFromAnnotation(Object obj) {
AnnotatedElement element = (obj instanceof AnnotatedElement ae ? ae : obj.getClass());
MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
if (order == null && obj instanceof DecoratingProxy decoratingProxy) {
return findOrderFromAnnotation(decoratingProxy.getDecoratedClass());
}
return order;
}
在 OrderUtils
的 getOrderFromAnnotations()
方法又调用了 findOrder()
方法,在盖方法中会先查找 @Order
注解,然后获取它的值;如果没有的话,则查找 @Priority
注解,然后获取它的值,如果都没有的话,则返回为空。
java
private static Integer findOrder(MergedAnnotations annotations) {
// 查找@Order 注解
MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
if (orderAnnotation.isPresent()) {
return orderAnnotation.getInt(MergedAnnotation.VALUE);
}
// 查找@Priority 注解
MergedAnnotation<?> priorityAnnotation = annotations.get(JAKARTA_PRIORITY_ANNOTATION);
if (priorityAnnotation.isPresent()) {
return priorityAnnotation.getInt(MergedAnnotation.VALUE);
}
return null;
}