diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 10ada74b3725..b6edb81fc818 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -119,6 +119,7 @@ * @author Phillip Webb * @author Stephane Nicoll * @author Sebastien Deleuze + * @author Yanming Zhou * @since 16 April 2001 * @see #registerBeanDefinition * @see #addBeanPostProcessor @@ -1806,6 +1807,10 @@ else if (Map.class.isAssignableFrom(type) && type.isInterface()) { if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } + Comparator comparator = adaptDependencyComparator(matchingBeans); + if (comparator != null) { + matchingBeans = sortMatchingBeans(matchingBeans, comparator); + } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); return converter.convertIfNecessary(matchingBeans, descriptor.getDependencyType()); } @@ -1819,6 +1824,16 @@ private boolean isRequired(DependencyDescriptor descriptor) { return getAutowireCandidateResolver().isRequired(descriptor); } + private Map sortMatchingBeans(Map matchingBeans, Comparator comparator) { + List> list = new ArrayList<>(matchingBeans.entrySet()); + list.sort(Map.Entry.comparingByValue(comparator)); + Map result = CollectionUtils.newLinkedHashMap(list.size()); + for(Map.Entry entry : list) { + result.put(entry.getKey(), entry.getValue()); + } + return result; + } + private @Nullable Comparator adaptDependencyComparator(Map matchingBeans) { Comparator comparator = getDependencyComparator(); if (comparator instanceof OrderComparator orderComparator) { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java index 7a8a43e4eac8..09cd64604fdb 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java @@ -62,6 +62,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.AutowireCandidateQualifier; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; @@ -93,6 +94,7 @@ * @author Sam Brannen * @author Chris Beams * @author Stephane Nicoll + * @author Yanming Zhou */ class AutowiredAnnotationBeanPostProcessorTests { @@ -1297,6 +1299,32 @@ void methodInjectionWithMap() { assertThat(bean.getTestBean()).isSameAs(tb); } + @Test + void mapInjectionShouldHonorTheSortingOrder() { + RootBeanDefinition bd = new RootBeanDefinition(MapMethodInjectionBean.class); + bf.registerBeanDefinition("annotatedBean", bd); + RootBeanDefinition bd1 = new RootBeanDefinition(); + bd1.setBeanClass(TestBean.class); + bd1.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.LOWEST_PRECEDENCE); + bf.registerBeanDefinition("bean1", bd1); + RootBeanDefinition bd2 = new RootBeanDefinition(); + bd2.setBeanClass(DerivedTestBean.class); + bd2.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.HIGHEST_PRECEDENCE); + bd2.setPrimary(true); + bf.registerBeanDefinition("bean2", bd2); + RootBeanDefinition bd3 = new RootBeanDefinition(); + bd3.setBeanClass(TestBean.class); + bd3.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.HIGHEST_PRECEDENCE + 1); + bf.registerBeanDefinition("bean3", bd3); + RootBeanDefinition bd4 = new RootBeanDefinition(); + bd4.setBeanClass(TestBean.class); + bd4.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.LOWEST_PRECEDENCE - 1); + bf.registerBeanDefinition("bean4", bd4); + + MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class); + assertThat(bean.getTestBeanMap().keySet()).containsExactly("bean2", "bean3", "bean4", "bean1"); + } + @Test void methodInjectionWithMapAndMultipleMatches() { bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));