diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 692571f5f0d..dee9a440a0b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -1458,7 +1458,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp // Cache the merged bean definition for the time being // (it might still get re-merged later on in order to pick up metadata changes) if (containingBd == null && (isCacheBeanMetadata() || isBeanEligibleForMetadataCaching(beanName))) { - this.mergedBeanDefinitions.put(beanName, mbd); + cacheMergedBeanDefinition(mbd, beanName); } } if (previous != null) { @@ -1487,6 +1487,18 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp } } + /** + * Cache the given merged bean definition. + *

Subclasses can override this to derive additional cached state + * from the final post-processed bean definition. + * @param mbd the merged bean definition to cache + * @param beanName the name of the bean + * @since 6.2.6 + */ + protected void cacheMergedBeanDefinition(RootBeanDefinition mbd, String beanName) { + this.mergedBeanDefinitions.put(beanName, mbd); + } + /** * Check the given merged bean definition, * potentially throwing validation exceptions. 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 8aa4231646f..17c757e01b0 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 @@ -1004,6 +1004,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto return super.obtainInstanceFromSupplier(supplier, beanName, mbd); } + @Override + protected void cacheMergedBeanDefinition(RootBeanDefinition mbd, String beanName) { + super.cacheMergedBeanDefinition(mbd, beanName); + if (mbd.isPrimary()) { + this.primaryBeanNames.add(beanName); + } + } + @Override protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object @Nullable [] args) { super.checkMergedBeanDefinition(mbd, beanName, args); 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 e88e982c623..7a8a43e4eac 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 @@ -1727,6 +1727,40 @@ class AutowiredAnnotationBeanPostProcessorTests { tb2.setFactoryMethodName("newTestBean2"); tb2.setLazyInit(true); bf.registerBeanDefinition("testBean2", tb2); + bf.registerAlias("testBean2", "testBean"); + + ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class); + TestBean testBean1 = bf.getBean("testBean1", TestBean.class); + assertThat(bean.getTestBean()).isSameAs(testBean1); + assertThat(bean.getOptionalTestBean()).isSameAs(testBean1); + assertThat(bean.consumeOptionalTestBean()).isSameAs(testBean1); + assertThat(bean.getUniqueTestBean()).isSameAs(testBean1); + assertThat(bean.consumeUniqueTestBean()).isSameAs(testBean1); + assertThat(bf.containsSingleton("testBean2")).isFalse(); + + TestBean testBean2 = bf.getBean("testBean2", TestBean.class); + assertThat(bean.iterateTestBeans()).containsExactly(testBean1, testBean2); + assertThat(bean.forEachTestBeans()).containsExactly(testBean1, testBean2); + assertThat(bean.streamTestBeans()).containsExactly(testBean1, testBean2); + assertThat(bean.streamTestBeansInOrder()).containsExactly(testBean2, testBean1); + assertThat(bean.allTestBeans()).containsExactly(testBean1, testBean2); + assertThat(bean.allTestBeansInOrder()).containsExactly(testBean2, testBean1); + assertThat(bean.allSingletonBeans()).containsExactly(testBean1, testBean2); + assertThat(bean.allSingletonBeansInOrder()).containsExactly(testBean2, testBean1); + } + + @Test + void objectProviderInjectionWithLateMarkedTargetPrimary() { + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class)); + RootBeanDefinition tb1 = new RootBeanDefinition(TestBeanFactory.class); + tb1.setFactoryMethodName("newTestBean1"); + bf.registerBeanDefinition("testBean1", tb1); + RootBeanDefinition tb2 = new RootBeanDefinition(TestBeanFactory.class); + tb2.setFactoryMethodName("newTestBean2"); + tb2.setLazyInit(true); + bf.registerBeanDefinition("testBean2", tb2); + bf.registerAlias("testBean2", "testBean"); + tb1.setPrimary(true); ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class); TestBean testBean1 = bf.getBean("testBean1", TestBean.class);