diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java index 4be7503b6f3..58e41b0d439 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java @@ -23,7 +23,6 @@ import java.util.Set; import org.springframework.aop.scope.ScopedProxyUtils; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; @@ -44,7 +43,7 @@ import org.springframework.util.Assert; /** * A {@link BeanFactoryPostProcessor} implementation that processes identified - * use of {@link BeanOverride @BeanOverride} and adapts the {@link BeanFactory} + * use of {@link BeanOverride @BeanOverride} and adapts the {@code BeanFactory} * accordingly. * *

For each override, the bean factory is prepared according to the chosen @@ -119,9 +118,16 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, // NOTE: This method supports 3 distinct scenarios which must be accounted for. // - // 1) JVM runtime - // 2) AOT processing - // 3) AOT runtime + // - JVM runtime + // - AOT processing + // - AOT runtime + // + // In addition, this method supports 4 distinct use cases. + // + // 1) Override existing bean by-type + // 2) Create bean by-type, with a generated name + // 3) Override existing bean by-name + // 4) Create bean by-name, with a provided name String beanName = handler.getBeanName(); Field field = handler.getField(); @@ -129,7 +135,7 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, if (beanName == null) { beanName = getBeanNameForType(beanFactory, handler, requireExistingBean); if (beanName != null) { - // We are overriding an existing bean by-type. + // 1) We are overriding an existing bean by-type. beanName = BeanFactoryUtils.transformedBeanName(beanName); // If we are overriding a manually registered singleton, we won't find // an existing bean definition. @@ -138,15 +144,16 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, } } else { - // We will later generate a name for the nonexistent bean, but since NullAway - // will reject leaving the beanName set to null, we set it to a placeholder. + // 2) We are creating a bean by-type, with a generated name. + // Since NullAway will reject leaving the beanName set to null, + // we set it to a placeholder that will be replaced later. beanName = PSEUDO_BEAN_NAME_PLACEHOLDER; } } else { Set candidates = getExistingBeanNamesByType(beanFactory, handler, false); if (candidates.contains(beanName)) { - // We are overriding an existing bean by-name. + // 3) We are overriding an existing bean by-name. existingBeanDefinition = beanFactory.getBeanDefinition(beanName); } else if (requireExistingBean) { @@ -156,6 +163,7 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, .formatted(beanName, handler.getBeanType(), field.getDeclaringClass().getSimpleName(), field.getName())); } + // 4) We are creating a bean by-name with the provided beanName. } if (existingBeanDefinition != null) { @@ -214,11 +222,14 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, /** * Check that a bean with the specified {@link BeanOverrideHandler#getBeanName() name} - * and {@link BeanOverrideHandler#getBeanType() type} is registered. - *

If so, put the {@link BeanOverrideHandler} in the early tracking map. - *

The map will later be checked to see if a given bean should be wrapped - * upon creation, during the {@link WrapEarlyBeanPostProcessor#getEarlyBeanReference} - * phase. + * or {@link BeanOverrideHandler#getBeanType() type} has already been registered + * in the {@code BeanFactory}. + *

If so, register the {@link BeanOverrideHandler} and the corresponding bean + * name in the {@link BeanOverrideRegistry}. + *

The registry will later be checked to see if a given bean should be wrapped + * upon creation, during the early bean post-processing phase. + * @see BeanOverrideRegistry#registerBeanOverrideHandler(BeanOverrideHandler, String) + * @see WrapEarlyBeanPostProcessor#getEarlyBeanReference(Object, String) */ private void wrapBean(ConfigurableListableBeanFactory beanFactory, BeanOverrideHandler handler) { String beanName = handler.getBeanName(); @@ -393,7 +404,7 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, * respectively. *

The returned bean definition should not be used to create * a bean instance but rather only for the purpose of having suitable bean - * definition metadata available in the {@link BeanFactory} — for example, + * definition metadata available in the {@code BeanFactory} — for example, * for autowiring candidate resolution. */ private static RootBeanDefinition createPseudoBeanDefinition(BeanOverrideHandler handler) {