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 80de1e3d25..236ec318b1 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 @@ -1082,7 +1082,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto } } for (String candidateName : candidateNames) { - if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) { + if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) { result.put(candidateName, getBean(candidateName)); } } @@ -1107,13 +1107,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto */ protected String determineAutowireCandidate(Map candidateBeans, DependencyDescriptor descriptor) { Class requiredType = descriptor.getDependencyType(); - String primaryCandidate = - determinePrimaryCandidate(candidateBeans, requiredType); + String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType); if (primaryCandidate != null) { return primaryCandidate; } - String priorityCandidate = - determineHighestPriorityCandidate(candidateBeans, requiredType); + String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType); if (priorityCandidate != null) { return priorityCandidate; } @@ -1240,6 +1238,23 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto (candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName))); } + /** + * Determine whether the given beanName/candidateName pair indicates a self reference, + * i.e. whether the candidate points back to the original bean or to a factory method + * on the original bean. + */ + private boolean isSelfReference(String beanName, String candidateName) { + if (beanName.equals(candidateName)) { + return true; + } + if (candidateName != null && containsBeanDefinition(candidateName)) { + if (beanName.equals(getMergedLocalBeanDefinition(candidateName).getFactoryBeanName())) { + return true; + } + } + return false; + } + /** * Raise a NoSuchBeanDefinitionException for an unresolvable dependency. */ diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java index 549584f3f4..278f0499b7 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java @@ -20,6 +20,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import javax.annotation.PostConstruct; import org.junit.Before; import org.junit.Test; @@ -40,6 +41,7 @@ import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.DescriptiveResource; import org.springframework.tests.sample.beans.ITestBean; import org.springframework.tests.sample.beans.TestBean; +import org.springframework.util.Assert; import static org.junit.Assert.*; @@ -362,10 +364,8 @@ public class ConfigurationClassPostProcessorTests { @Test public void genericsBasedInjectionWithWildcardWithExtendsMatch() { - beanFactory.registerBeanDefinition("configClass", - new RootBeanDefinition(WildcardWithExtendsConfiguration.class)); - ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor(); - pp.postProcessBeanFactory(beanFactory); + beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithExtendsConfiguration.class)); + new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory); assertSame(beanFactory.getBean("stringRepo"), beanFactory.getBean("repoConsumer")); } @@ -373,8 +373,7 @@ public class ConfigurationClassPostProcessorTests { @Test public void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() { beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithGenericExtendsConfiguration.class)); - ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor(); - pp.postProcessBeanFactory(beanFactory); + new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory); assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer")); } @@ -388,6 +387,18 @@ public class ConfigurationClassPostProcessorTests { assertNotNull(simpleComponent); } + @Test + public void testSelfReferenceExclusionForFactoryMethodOnSameBean() { + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(beanFactory); + beanFactory.addBeanPostProcessor(bpp); + beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor()); + beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ConcreteConfig.class)); + beanFactory.registerBeanDefinition("serviceBeanProvider", new RootBeanDefinition(ServiceBeanProvider.class)); + new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory); + beanFactory.preInstantiateSingletons(); + } + // ------------------------------------------------------------------------- @@ -412,7 +423,6 @@ public class ConfigurationClassPostProcessorTests { final Foo foo; - public Bar(Foo foo) { this.foo = foo; } @@ -492,7 +502,6 @@ public class ConfigurationClassPostProcessorTests { @Bean public Repository stringRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -503,7 +512,6 @@ public class ConfigurationClassPostProcessorTests { @Bean public Repository integerRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -514,7 +522,6 @@ public class ConfigurationClassPostProcessorTests { @Bean public Repository genericRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -530,7 +537,6 @@ public class ConfigurationClassPostProcessorTests { @Scope("prototype") public Repository stringRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -542,7 +548,6 @@ public class ConfigurationClassPostProcessorTests { @Scope("prototype") public Repository integerRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -555,7 +560,6 @@ public class ConfigurationClassPostProcessorTests { @SuppressWarnings("rawtypes") public Repository genericRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -756,4 +760,57 @@ public class ConfigurationClassPostProcessorTests { MetaComponentScanConfigurationWithAttributeOverridesClass { } + public static class ServiceBean { + + private final String parameter; + + public ServiceBean(String parameter) { + this.parameter = parameter; + } + + public String getParameter() { + return parameter; + } + } + + @Configuration + public static abstract class AbstractConfig { + + @Bean + public ServiceBean serviceBean() { + return provider().getServiceBean(); + } + + @Bean + public ServiceBeanProvider provider() { + return new ServiceBeanProvider(); + } + } + + @Configuration + public static class ConcreteConfig extends AbstractConfig { + + @Autowired + private ServiceBeanProvider provider; + + @Bean + @Override + public ServiceBeanProvider provider() { + return provider; + } + + @PostConstruct + public void validate() { + Assert.notNull(provider); + } + } + + @Primary + public static class ServiceBeanProvider { + + public ServiceBean getServiceBean() { + return new ServiceBean("message"); + } + } } +