@ -35,6 +35,7 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
@@ -35,6 +35,7 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultBeanNameGenerator ;
import org.springframework.beans.factory.support.DefaultListableBeanFactory ;
import org.springframework.beans.factory.support.RootBeanDefinition ;
import org.springframework.context.aot.AbstractAotProcessor ;
import org.springframework.core.Ordered ;
import org.springframework.core.ResolvableType ;
import org.springframework.lang.Nullable ;
@ -105,6 +106,12 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
@@ -105,6 +106,12 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
private void replaceDefinition ( ConfigurableListableBeanFactory beanFactory , OverrideMetadata overrideMetadata ,
boolean enforceExistingDefinition ) {
// NOTE: This method supports 3 distinct scenarios which must be accounted for.
//
// 1) JVM runtime
// 2) AOT processing
// 3) AOT runtime
if ( ! ( beanFactory instanceof BeanDefinitionRegistry registry ) ) {
throw new IllegalStateException ( "Cannot process bean override with a BeanFactory " +
"that doesn't implement BeanDefinitionRegistry: " + beanFactory . getClass ( ) . getName ( ) ) ;
@ -147,12 +154,24 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
@@ -147,12 +154,24 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
if ( existingBeanDefinition ! = null ) {
// Validate the existing bean definition.
//
// Applies during "JVM runtime", "AOT processing", and "AOT runtime".
validateBeanDefinition ( beanFactory , beanName ) ;
}
else if ( Boolean . getBoolean ( AbstractAotProcessor . AOT_PROCESSING ) ) {
// There was no existing bean definition, but during "AOT processing" we
// do not register the "pseudo" bean definition since our AOT support
// cannot automatically convert that to a functional bean definition for
// use at "AOT runtime". Furthermore, by not registering a bean definition
// for a nonexistent bean, we allow the "JVM runtime" and "AOT runtime"
// to operate the same in the following else-block.
}
else {
// There was no existing bean definition, so we register the "pseudo" bean
// definition to ensure that a suitable bean definition exists for the given
// bean name for proper autowiring candidate resolution.
//
// Applies during "JVM runtime" and "AOT runtime".
registry . registerBeanDefinition ( beanName , pseudoBeanDefinition ) ;
}
@ -163,6 +182,11 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
@@ -163,6 +182,11 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
// Now we have an instance (the override) that we can register. At this stage, we don't
// expect a singleton instance to be present. If for some reason a singleton instance
// already exists, the following will throw an exception.
//
// As a bonus, by manually registering a singleton during "AOT processing", we allow
// GenericApplicationContext's preDetermineBeanType() method to transparently register
// runtime hints for a proxy generated by the above createOverride() invocation --
// for example, when @MockitoBean creates a mock based on a JDK dynamic proxy.
beanFactory . registerSingleton ( beanName , override ) ;
}