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 048612fbed73..0377ee35aab2 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1647,28 +1647,36 @@ protected String determineAutowireCandidate(Map candidates, Depe * (or candidate classes if not created yet) that match the required type * @param requiredType the target dependency type to match against * @return the name of the primary candidate, or {@code null} if none found - * @see #isPrimary(String, Object) */ @Nullable protected String determinePrimaryCandidate(Map candidates, Class requiredType) { String primaryBeanName = null; + DefaultListableBeanFactory primaryBeanFactory = null; for (Map.Entry entry : candidates.entrySet()) { String candidateBeanName = entry.getKey(); - Object beanInstance = entry.getValue(); - if (isPrimary(candidateBeanName, beanInstance)) { - if (primaryBeanName != null) { - boolean candidateLocal = containsBeanDefinition(candidateBeanName); - boolean primaryLocal = containsBeanDefinition(primaryBeanName); - if (candidateLocal && primaryLocal) { - throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), - "more than one 'primary' bean found among candidates: " + candidates.keySet()); - } - else if (candidateLocal) { - primaryBeanName = candidateBeanName; - } + DefaultListableBeanFactory beanFactory = this; + boolean isPrimary = false; + while (beanFactory != primaryBeanFactory) { + String transformedCandidateBeanName = beanFactory.transformedBeanName(candidateBeanName); + if (beanFactory.containsBeanDefinition(transformedCandidateBeanName)) { + isPrimary = beanFactory.getMergedLocalBeanDefinition(transformedCandidateBeanName).isPrimary(); + break; } else { - primaryBeanName = candidateBeanName; + BeanFactory parent = beanFactory.getParentBeanFactory(); + beanFactory = parent instanceof DefaultListableBeanFactory ? (DefaultListableBeanFactory) parent : null; + } + } + if (isPrimary) { + primaryBeanName = candidateBeanName; + primaryBeanFactory = beanFactory; + } + else if (beanFactory == primaryBeanFactory && null != beanFactory){ + String transformedCandidateBeanName = beanFactory.transformedBeanName(candidateBeanName); + if(beanFactory.containsBeanDefinition(transformedCandidateBeanName) && + beanFactory.getMergedLocalBeanDefinition(transformedCandidateBeanName).isPrimary()) { + throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), + "more than one 'primary' bean found among candidates: " + candidates.keySet()); } } } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java index 13321a7e9a2e..03f5a38640a2 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1979,6 +1979,35 @@ void autowireBeanByTypeWithTwoPrimaryCandidates() { .withCauseExactlyInstanceOf(NoUniqueBeanDefinitionException.class); } + @Test + void autowireBeanByTypeWithTwoPrimaryCandidatesInOneAncestor() { + DefaultListableBeanFactory parent = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); + bd.setPrimary(true); + RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class); + bd2.setPrimary(true); + parent.registerBeanDefinition("test", bd); + parent.registerBeanDefinition("spouse", bd2); + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(parent); + assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() -> + lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true)) + .withCauseExactlyInstanceOf(NoUniqueBeanDefinitionException.class); + } + + @Test + void autowireBeanByTypeWithTwoPrimaryFactoryBeans(){ + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + RootBeanDefinition bd1 = new RootBeanDefinition(LazyInitFactory.class); + RootBeanDefinition bd2 = new RootBeanDefinition(LazyInitFactory.class); + bd1.setPrimary(true); + bd2.setPrimary(true); + lbf.registerBeanDefinition("bd1", bd1); + lbf.registerBeanDefinition("bd2", bd2); + assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() -> + lbf.autowire(FactoryBeanDependentBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true)) + .withCauseExactlyInstanceOf(NoUniqueBeanDefinitionException.class); + } + @Test void autowireBeanByTypeWithTwoMatchesAndPriority() { lbf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);