Browse Source

Merge branch '6.1.x'

pull/33697/head
Sam Brannen 1 year ago
parent
commit
68d9e5d81a
  1. 15
      spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
  2. 83
      spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java

15
spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

@ -1996,12 +1996,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
* @param requiredType the target dependency type to match against * @param requiredType the target dependency type to match against
* @return the name of the candidate with the highest priority, * @return the name of the candidate with the highest priority,
* or {@code null} if none found * or {@code null} if none found
* @throws NoUniqueBeanDefinitionException if multiple beans are detected with
* the same highest priority value
* @see #getPriority(Object) * @see #getPriority(Object)
*/ */
@Nullable @Nullable
protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) { protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String highestPriorityBeanName = null; String highestPriorityBeanName = null;
Integer highestPriority = null; Integer highestPriority = null;
boolean highestPriorityConflictDetected = false;
for (Map.Entry<String, Object> entry : candidates.entrySet()) { for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey(); String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue(); Object beanInstance = entry.getValue();
@ -2010,13 +2013,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (candidatePriority != null) { if (candidatePriority != null) {
if (highestPriority != null) { if (highestPriority != null) {
if (candidatePriority.equals(highestPriority)) { if (candidatePriority.equals(highestPriority)) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), highestPriorityConflictDetected = true;
"Multiple beans found with the same priority ('" + highestPriority +
"') among candidates: " + candidates.keySet());
} }
else if (candidatePriority < highestPriority) { else if (candidatePriority < highestPriority) {
highestPriorityBeanName = candidateBeanName; highestPriorityBeanName = candidateBeanName;
highestPriority = candidatePriority; highestPriority = candidatePriority;
highestPriorityConflictDetected = false;
} }
} }
else { else {
@ -2026,6 +2028,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
} }
} }
} }
if (highestPriorityConflictDetected) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"Multiple beans found with the same highest priority (" + highestPriority +
") among candidates: " + candidates.keySet());
}
return highestPriorityBeanName; return highestPriorityBeanName;
} }

83
spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java

@ -1718,18 +1718,73 @@ class DefaultListableBeanFactoryTests {
assertThat(bean.getBeanName()).isEqualTo("bd1"); assertThat(bean.getBeanName()).isEqualTo("bd1");
} }
/**
* {@code determineHighestPriorityCandidate()} should reject duplicate
* priorities for the highest priority detected.
*
* @see #getBeanByTypeWithMultipleNonHighestPriorityCandidates()
*/
@Test @Test
void getBeanByTypeWithMultiplePriority() { void getBeanByTypeWithMultipleHighestPriorityCandidates() {
lbf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); lbf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
RootBeanDefinition bd1 = new RootBeanDefinition(HighPriorityTestBean.class); RootBeanDefinition bd1 = new RootBeanDefinition(HighPriorityTestBean.class);
RootBeanDefinition bd2 = new RootBeanDefinition(HighPriorityTestBean.class); RootBeanDefinition bd2 = new RootBeanDefinition(LowPriorityTestBean.class);
RootBeanDefinition bd3 = new RootBeanDefinition(HighPriorityTestBean.class);
lbf.registerBeanDefinition("bd1", bd1); lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2); lbf.registerBeanDefinition("bd2", bd2);
lbf.registerBeanDefinition("bd3", bd3);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class) assertThatExceptionOfType(NoUniqueBeanDefinitionException.class)
.isThrownBy(() -> lbf.getBean(TestBean.class)) .isThrownBy(() -> lbf.getBean(TestBean.class))
.withMessageContaining("Multiple beans found with the same priority") .withMessageContaining("Multiple beans found with the same highest priority (5) among candidates: ");
.withMessageContaining("5"); // conflicting priority }
/**
* {@code determineHighestPriorityCandidate()} should ignore duplicate
* priorities for any priority other than the highest, and the order in
* which beans is declared should not affect the outcome.
*
* @see #getBeanByTypeWithMultipleHighestPriorityCandidates()
*/
@Test // gh-33733
void getBeanByTypeWithMultipleNonHighestPriorityCandidates() {
getBeanByTypeWithMultipleNonHighestPriorityCandidates(
PriorityService1.class,
PriorityService2A.class,
PriorityService2B.class,
PriorityService3.class
);
getBeanByTypeWithMultipleNonHighestPriorityCandidates(
PriorityService3.class,
PriorityService2B.class,
PriorityService2A.class,
PriorityService1.class
);
getBeanByTypeWithMultipleNonHighestPriorityCandidates(
PriorityService2A.class,
PriorityService1.class,
PriorityService2B.class,
PriorityService3.class
);
getBeanByTypeWithMultipleNonHighestPriorityCandidates(
PriorityService2A.class,
PriorityService3.class,
PriorityService1.class,
PriorityService2B.class
);
}
private void getBeanByTypeWithMultipleNonHighestPriorityCandidates(Class<?>... classes) {
lbf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
for (Class<?> clazz : classes) {
lbf.registerBeanDefinition(clazz.getSimpleName(), new RootBeanDefinition(clazz));
}
PriorityService bean = lbf.getBean(PriorityService.class);
assertThat(bean).isExactlyInstanceOf(PriorityService1.class);
} }
@Test @Test
@ -3519,6 +3574,26 @@ class DefaultListableBeanFactoryTests {
} }
interface PriorityService {
}
@Priority(1)
static class PriorityService1 implements PriorityService {
}
@Priority(2)
static class PriorityService2A implements PriorityService {
}
@Priority(2)
static class PriorityService2B implements PriorityService {
}
@Priority(3)
static class PriorityService3 implements PriorityService {
}
@Priority(5) @Priority(5)
private static class HighPriorityTestBean extends TestBean { private static class HighPriorityTestBean extends TestBean {
} }

Loading…
Cancel
Save