|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2021 the original author or authors. |
| 2 | + * Copyright 2002-2022 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
18 | 18 |
|
19 | 19 | import java.util.ArrayList;
|
20 | 20 | import java.util.Arrays;
|
| 21 | +import java.util.HashMap; |
21 | 22 | import java.util.HashSet;
|
22 | 23 | import java.util.LinkedHashMap;
|
23 | 24 | import java.util.LinkedHashSet;
|
24 | 25 | import java.util.List;
|
25 | 26 | import java.util.Map;
|
26 | 27 | import java.util.Set;
|
27 | 28 |
|
| 29 | +import javax.lang.model.element.Modifier; |
| 30 | + |
28 | 31 | import org.apache.commons.logging.Log;
|
29 | 32 | import org.apache.commons.logging.LogFactory;
|
30 | 33 |
|
31 | 34 | import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
|
| 35 | +import org.springframework.aot.hint.ResourceHints; |
| 36 | +import org.springframework.aot.hint.TypeReference; |
32 | 37 | import org.springframework.beans.PropertyValues;
|
33 | 38 | import org.springframework.beans.factory.BeanClassLoaderAware;
|
34 | 39 | import org.springframework.beans.factory.BeanDefinitionStoreException;
|
|
40 | 45 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
41 | 46 | import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
|
42 | 47 | import org.springframework.beans.factory.config.SingletonBeanRegistry;
|
| 48 | +import org.springframework.beans.factory.generator.AotContributingBeanFactoryPostProcessor; |
| 49 | +import org.springframework.beans.factory.generator.BeanFactoryContribution; |
| 50 | +import org.springframework.beans.factory.generator.BeanFactoryInitialization; |
43 | 51 | import org.springframework.beans.factory.parsing.FailFastProblemReporter;
|
44 | 52 | import org.springframework.beans.factory.parsing.PassThroughSourceExtractor;
|
45 | 53 | import org.springframework.beans.factory.parsing.ProblemReporter;
|
|
65 | 73 | import org.springframework.core.type.MethodMetadata;
|
66 | 74 | import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
67 | 75 | import org.springframework.core.type.classreading.MetadataReaderFactory;
|
| 76 | +import org.springframework.javapoet.CodeBlock; |
| 77 | +import org.springframework.javapoet.CodeBlock.Builder; |
| 78 | +import org.springframework.javapoet.MethodSpec; |
| 79 | +import org.springframework.javapoet.ParameterizedTypeName; |
68 | 80 | import org.springframework.lang.Nullable;
|
69 | 81 | import org.springframework.util.Assert;
|
70 | 82 | import org.springframework.util.ClassUtils;
|
|
89 | 101 | * @since 3.0
|
90 | 102 | */
|
91 | 103 | public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
|
92 |
| - PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware { |
| 104 | + AotContributingBeanFactoryPostProcessor, PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, |
| 105 | + BeanClassLoaderAware, EnvironmentAware { |
93 | 106 |
|
94 | 107 | /**
|
95 | 108 | * A {@code BeanNameGenerator} using fully qualified class names as default bean names.
|
@@ -269,6 +282,12 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
269 | 282 | beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
|
270 | 283 | }
|
271 | 284 |
|
| 285 | + @Override |
| 286 | + public BeanFactoryContribution contribute(ConfigurableListableBeanFactory beanFactory) { |
| 287 | + return (beanFactory.containsBean(IMPORT_REGISTRY_BEAN_NAME) |
| 288 | + ? new ImportAwareBeanFactoryConfiguration(beanFactory) : null); |
| 289 | + } |
| 290 | + |
272 | 291 | /**
|
273 | 292 | * Build and validate a configuration model based on the registry of
|
274 | 293 | * {@link Configuration} classes.
|
@@ -485,4 +504,55 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
485 | 504 | }
|
486 | 505 | }
|
487 | 506 |
|
| 507 | + private static final class ImportAwareBeanFactoryConfiguration implements BeanFactoryContribution { |
| 508 | + |
| 509 | + private final ConfigurableListableBeanFactory beanFactory; |
| 510 | + |
| 511 | + private ImportAwareBeanFactoryConfiguration(ConfigurableListableBeanFactory beanFactory) { |
| 512 | + this.beanFactory = beanFactory; |
| 513 | + } |
| 514 | + |
| 515 | + |
| 516 | + @Override |
| 517 | + public void applyTo(BeanFactoryInitialization initialization) { |
| 518 | + Map<String, String> mappings = buildImportAwareMappings(); |
| 519 | + if (!mappings.isEmpty()) { |
| 520 | + MethodSpec method = initialization.generatedTypeContext().getMainGeneratedType() |
| 521 | + .addMethod(beanPostProcessorMethod(mappings)); |
| 522 | + initialization.contribute(code -> code.addStatement("beanFactory.addBeanPostProcessor($N())", method)); |
| 523 | + ResourceHints resourceHints = initialization.generatedTypeContext().runtimeHints().resources(); |
| 524 | + mappings.forEach((target, importedFrom) -> resourceHints.registerType( |
| 525 | + TypeReference.of(importedFrom))); |
| 526 | + } |
| 527 | + } |
| 528 | + |
| 529 | + private MethodSpec.Builder beanPostProcessorMethod(Map<String, String> mappings) { |
| 530 | + Builder code = CodeBlock.builder(); |
| 531 | + code.addStatement("$T mappings = new $T<>()", ParameterizedTypeName.get( |
| 532 | + Map.class, String.class, String.class), HashMap.class); |
| 533 | + mappings.forEach((key, value) -> code.addStatement("mappings.put($S, $S)", key, value)); |
| 534 | + code.addStatement("return new $T($L)", ImportAwareAotBeanPostProcessor.class, "mappings"); |
| 535 | + return MethodSpec.methodBuilder("createImportAwareBeanPostProcessor") |
| 536 | + .returns(ImportAwareAotBeanPostProcessor.class) |
| 537 | + .addModifiers(Modifier.PRIVATE).addCode(code.build()); |
| 538 | + } |
| 539 | + |
| 540 | + private Map<String, String> buildImportAwareMappings() { |
| 541 | + ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class); |
| 542 | + Map<String, String> mappings = new LinkedHashMap<>(); |
| 543 | + for (String name : this.beanFactory.getBeanDefinitionNames()) { |
| 544 | + Class<?> beanType = this.beanFactory.getType(name); |
| 545 | + if (beanType != null && ImportAware.class.isAssignableFrom(beanType)) { |
| 546 | + String type = ClassUtils.getUserClass(beanType).getName(); |
| 547 | + AnnotationMetadata importingClassMetadata = ir.getImportingClassFor(type); |
| 548 | + if (importingClassMetadata != null) { |
| 549 | + mappings.put(type, importingClassMetadata.getClassName()); |
| 550 | + } |
| 551 | + } |
| 552 | + } |
| 553 | + return mappings; |
| 554 | + } |
| 555 | + |
| 556 | + } |
| 557 | + |
488 | 558 | }
|
0 commit comments