Add support for ImportAware in BeanRegistrar

Closes gh-34627
This commit is contained in:
Sébastien Deleuze
2025-03-21 11:49:15 +01:00
parent 3e788e4ca1
commit 5ce64f47b2
10 changed files with 196 additions and 21 deletions

View File

@@ -66,7 +66,7 @@ final class ConfigurationClass {
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
new LinkedHashMap<>();
private final Set<BeanRegistrar> beanRegistrars = new LinkedHashSet<>();
private final Map<String, BeanRegistrar> beanRegistrars = new LinkedHashMap<>();
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
new LinkedHashMap<>();
@@ -222,11 +222,11 @@ final class ConfigurationClass {
return this.importedResources;
}
void addBeanRegistrar(BeanRegistrar beanRegistrar) {
this.beanRegistrars.add(beanRegistrar);
void addBeanRegistrar(String sourceClassName, BeanRegistrar beanRegistrar) {
this.beanRegistrars.put(sourceClassName, beanRegistrar);
}
public Set<BeanRegistrar> getBeanRegistrars() {
public Map<String, BeanRegistrar> getBeanRegistrars() {
return this.beanRegistrars;
}

View File

@@ -404,11 +404,11 @@ class ConfigurationClassBeanDefinitionReader {
registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}
private void loadBeanDefinitionsFromBeanRegistrars(Set<BeanRegistrar> registrars) {
private void loadBeanDefinitionsFromBeanRegistrars(Map<String, BeanRegistrar> registrars) {
Assert.isInstanceOf(ListableBeanFactory.class, this.registry,
"Cannot support bean registrars since " + this.registry.getClass().getName() +
" does not implement BeanDefinitionRegistry");
registrars.forEach(registrar -> registrar.register(new BeanRegistryAdapter(this.registry,
registrars.values().forEach(registrar -> registrar.register(new BeanRegistryAdapter(this.registry,
(ListableBeanFactory) this.registry, this.environment, registrar.getClass()), this.environment));
}

View File

@@ -602,7 +602,11 @@ class ConfigurationClassParser {
else if (candidate.isAssignable(BeanRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
BeanRegistrar registrar = (BeanRegistrar) BeanUtils.instantiateClass(candidateClass);
configClass.addBeanRegistrar(registrar);
AnnotationMetadata metadata = currentSourceClass.getMetadata();
if (registrar instanceof ImportAware importAware) {
importAware.setImportMetadata(metadata);
}
configClass.addBeanRegistrar(metadata.getClassName(), registrar);
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->

View File

@@ -114,6 +114,7 @@ import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.CodeBlock.Builder;
import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.NameAllocator;
import org.springframework.javapoet.ParameterizedTypeName;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -122,6 +123,7 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* {@link BeanFactoryPostProcessor} used for bootstrapping processing of
@@ -197,7 +199,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
@SuppressWarnings("NullAway.Init")
private List<PropertySourceDescriptor> propertySourceDescriptors;
private Set<BeanRegistrar> beanRegistrars = new LinkedHashSet<>();
private Map<String, BeanRegistrar> beanRegistrars = new LinkedHashMap<>();
@Override
@@ -443,7 +445,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
}
this.reader.loadBeanDefinitions(configClasses);
for (ConfigurationClass configClass : configClasses) {
this.beanRegistrars.addAll(configClass.getBeanRegistrars());
this.beanRegistrars.putAll(configClass.getBeanRegistrars());
}
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
@@ -846,13 +848,13 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
private static final String ENVIRONMENT_VARIABLE = "environment";
private final Set<BeanRegistrar> beanRegistrars;
private final Map<String, BeanRegistrar> beanRegistrars;
private final ConfigurableListableBeanFactory beanFactory;
private final AotServices<BeanRegistrationAotProcessor> aotProcessors;
public BeanRegistrarAotContribution(Set<BeanRegistrar> beanRegistrars, ConfigurableListableBeanFactory beanFactory) {
public BeanRegistrarAotContribution(Map<String, BeanRegistrar> beanRegistrars, ConfigurableListableBeanFactory beanFactory) {
this.beanRegistrars = beanRegistrars;
this.beanFactory = beanFactory;
this.aotProcessors = AotServices.factoriesAndBeans(this.beanFactory).load(BeanRegistrationAotProcessor.class);
@@ -935,13 +937,32 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
private CodeBlock generateRegisterCode() {
Builder code = CodeBlock.builder();
for (BeanRegistrar beanRegistrar : this.beanRegistrars) {
code.addStatement("new $T().register(new $T(($T)$L, $L, $L, $T.class, $L), $L)", beanRegistrar.getClass(),
Builder metadataReaderFactoryCode = null;
NameAllocator nameAllocator = new NameAllocator();
for (Map.Entry<String, BeanRegistrar> beanRegistrarEntry : this.beanRegistrars.entrySet()) {
BeanRegistrar beanRegistrar = beanRegistrarEntry.getValue();
String beanRegistrarName = nameAllocator.newName(StringUtils.uncapitalize(beanRegistrar.getClass().getSimpleName()));
code.addStatement("$T $L = new $T()", beanRegistrar.getClass(), beanRegistrarName, beanRegistrar.getClass());
if (beanRegistrar instanceof ImportAware) {
if (metadataReaderFactoryCode == null) {
metadataReaderFactoryCode = CodeBlock.builder();
metadataReaderFactoryCode.addStatement("$T metadataReaderFactory = new $T()",
MetadataReaderFactory.class, CachingMetadataReaderFactory.class);
}
code.beginControlFlow("try")
.addStatement("$L.setImportMetadata(metadataReaderFactory.getMetadataReader($S).getAnnotationMetadata())",
beanRegistrarName, beanRegistrarEntry.getKey())
.nextControlFlow("catch ($T ex)", IOException.class)
.addStatement("throw new $T(\"Failed to read metadata for '$L'\", ex)",
IllegalStateException.class, beanRegistrarEntry.getKey())
.endControlFlow();
}
code.addStatement("$L.register(new $T(($T)$L, $L, $L, $T.class, $L), $L)", beanRegistrarName,
BeanRegistryAdapter.class, BeanDefinitionRegistry.class, BeanFactoryInitializationCode.BEAN_FACTORY_VARIABLE,
BeanFactoryInitializationCode.BEAN_FACTORY_VARIABLE, ENVIRONMENT_VARIABLE, beanRegistrar.getClass(),
CUSTOMIZER_MAP_VARIABLE, ENVIRONMENT_VARIABLE);
}
return code.build();
return (metadataReaderFactoryCode == null ? code.build() : metadataReaderFactoryCode.add(code.build()).build());
}
private CodeBlock generateInitDestroyMethods(String beanName, AbstractBeanDefinition beanDefinition,