16
16
17
17
package org .springframework .context .annotation ;
18
18
19
+ import java .io .IOException ;
20
+ import java .io .UncheckedIOException ;
19
21
import java .util .ArrayList ;
20
22
import java .util .HashMap ;
21
23
import java .util .HashSet ;
65
67
import org .springframework .context .annotation .ConfigurationClassEnhancer .EnhancedConfiguration ;
66
68
import org .springframework .core .Ordered ;
67
69
import org .springframework .core .PriorityOrdered ;
70
+ import org .springframework .core .env .ConfigurableEnvironment ;
68
71
import org .springframework .core .env .Environment ;
69
72
import org .springframework .core .env .StandardEnvironment ;
70
73
import org .springframework .core .io .DefaultResourceLoader ;
71
74
import org .springframework .core .io .ResourceLoader ;
75
+ import org .springframework .core .io .support .PropertySourceDescriptor ;
76
+ import org .springframework .core .io .support .PropertySourceProcessor ;
72
77
import org .springframework .core .metrics .ApplicationStartup ;
73
78
import org .springframework .core .metrics .StartupStep ;
74
79
import org .springframework .core .type .AnnotationMetadata ;
75
80
import org .springframework .core .type .MethodMetadata ;
76
81
import org .springframework .core .type .classreading .CachingMetadataReaderFactory ;
77
82
import org .springframework .core .type .classreading .MetadataReaderFactory ;
78
83
import org .springframework .javapoet .CodeBlock ;
84
+ import org .springframework .javapoet .CodeBlock .Builder ;
79
85
import org .springframework .javapoet .MethodSpec ;
80
86
import org .springframework .javapoet .ParameterizedTypeName ;
81
87
import org .springframework .lang .Nullable ;
82
88
import org .springframework .util .Assert ;
83
89
import org .springframework .util .ClassUtils ;
90
+ import org .springframework .util .CollectionUtils ;
84
91
85
92
/**
86
93
* {@link BeanFactoryPostProcessor} used for bootstrapping processing of
@@ -156,6 +163,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
156
163
157
164
private ApplicationStartup applicationStartup = ApplicationStartup .DEFAULT ;
158
165
166
+ @ Nullable
167
+ private List <PropertySourceDescriptor > propertySourceDescriptors ;
168
+
159
169
160
170
@ Override
161
171
public int getOrder () {
@@ -285,7 +295,19 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
285
295
286
296
@ Override
287
297
public BeanFactoryInitializationAotContribution processAheadOfTime (ConfigurableListableBeanFactory beanFactory ) {
288
- return (beanFactory .containsBean (IMPORT_REGISTRY_BEAN_NAME ) ? new AotContribution (beanFactory ) : null );
298
+ boolean hasPropertySourceDescriptors = !CollectionUtils .isEmpty (this .propertySourceDescriptors );
299
+ boolean hasImportRegistry = beanFactory .containsBean (IMPORT_REGISTRY_BEAN_NAME );
300
+ if (hasPropertySourceDescriptors || hasImportRegistry ) {
301
+ return (generationContext , code ) -> {
302
+ if (hasPropertySourceDescriptors ) {
303
+ new PropertySourcesAotContribution (this .propertySourceDescriptors ).applyTo (generationContext , code );
304
+ }
305
+ if (hasImportRegistry ) {
306
+ new ImportAwareAotContribution (beanFactory ).applyTo (generationContext , code );
307
+ }
308
+ };
309
+ }
310
+ return null ;
289
311
}
290
312
291
313
/**
@@ -390,6 +412,9 @@ else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.
390
412
sbr .registerSingleton (IMPORT_REGISTRY_BEAN_NAME , parser .getImportRegistry ());
391
413
}
392
414
415
+ // Store the PropertySourceDescriptors to contribute them Ahead-of-time if necessary
416
+ this .propertySourceDescriptors = parser .getPropertySourceDescriptors ();
417
+
393
418
if (this .metadataReaderFactory instanceof CachingMetadataReaderFactory cachingMetadataReaderFactory ) {
394
419
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
395
420
// for a shared cache since it'll be cleared by the ApplicationContext.
@@ -422,7 +447,7 @@ public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFact
422
447
// or component class without @Bean methods.
423
448
boolean liteConfigurationCandidateWithoutBeanMethods =
424
449
(ConfigurationClassUtils .CONFIGURATION_CLASS_LITE .equals (configClassAttr ) &&
425
- annotationMetadata != null && !ConfigurationClassUtils .hasBeanMethods (annotationMetadata ));
450
+ annotationMetadata != null && !ConfigurationClassUtils .hasBeanMethods (annotationMetadata ));
426
451
if (!liteConfigurationCandidateWithoutBeanMethods ) {
427
452
try {
428
453
abd .resolveBeanClass (this .beanClassLoader );
@@ -505,7 +530,7 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) {
505
530
}
506
531
507
532
508
- private static class AotContribution implements BeanFactoryInitializationAotContribution {
533
+ private static class ImportAwareAotContribution implements BeanFactoryInitializationAotContribution {
509
534
510
535
private static final String BEAN_FACTORY_VARIABLE = BeanFactoryInitializationCode .BEAN_FACTORY_VARIABLE ;
511
536
@@ -520,7 +545,7 @@ private static class AotContribution implements BeanFactoryInitializationAotCont
520
545
521
546
private final ConfigurableListableBeanFactory beanFactory ;
522
547
523
- public AotContribution (ConfigurableListableBeanFactory beanFactory ) {
548
+ public ImportAwareAotContribution (ConfigurableListableBeanFactory beanFactory ) {
524
549
this .beanFactory = beanFactory ;
525
550
}
526
551
@@ -585,4 +610,82 @@ private Map<String, String> buildImportAwareMappings() {
585
610
586
611
}
587
612
613
+ private static class PropertySourcesAotContribution implements BeanFactoryInitializationAotContribution {
614
+
615
+ private static final String ENVIRONMENT_VARIABLE = "environment" ;
616
+
617
+ private static final String RESOURCE_LOADER_VARIABLE = "resourceLoader" ;
618
+
619
+ private final List <PropertySourceDescriptor > descriptors ;
620
+
621
+ PropertySourcesAotContribution (List <PropertySourceDescriptor > descriptors ) {
622
+ this .descriptors = descriptors ;
623
+ }
624
+
625
+ @ Override
626
+ public void applyTo (GenerationContext generationContext , BeanFactoryInitializationCode beanFactoryInitializationCode ) {
627
+ GeneratedMethod generatedMethod = beanFactoryInitializationCode
628
+ .getMethods ()
629
+ .add ("processPropertySources" , this ::generateAddPropertySourceProcessorMethod );
630
+ beanFactoryInitializationCode
631
+ .addInitializer (generatedMethod .toMethodReference ());
632
+ }
633
+
634
+ private void generateAddPropertySourceProcessorMethod (MethodSpec .Builder method ) {
635
+ method .addJavadoc ("Apply known @PropertySources to the environment." );
636
+ method .addModifiers (Modifier .PRIVATE );
637
+ method .addParameter (ConfigurableEnvironment .class , ENVIRONMENT_VARIABLE );
638
+ method .addParameter (ResourceLoader .class , RESOURCE_LOADER_VARIABLE );
639
+ method .addCode (generateAddPropertySourceProcessorCode ());
640
+ }
641
+
642
+ private CodeBlock generateAddPropertySourceProcessorCode () {
643
+ Builder code = CodeBlock .builder ();
644
+ String processorVariable = "processor" ;
645
+ code .addStatement ("$T $L = new $T($L, $L)" , PropertySourceProcessor .class ,
646
+ processorVariable , PropertySourceProcessor .class , ENVIRONMENT_VARIABLE ,
647
+ RESOURCE_LOADER_VARIABLE );
648
+ code .beginControlFlow ("try" );
649
+ for (PropertySourceDescriptor descriptor : this .descriptors ) {
650
+ code .addStatement ("$L.processPropertySource($L)" , processorVariable ,
651
+ generatePropertySourceDescriptorCode (descriptor ));
652
+ }
653
+ code .nextControlFlow ("catch ($T ex)" , IOException .class );
654
+ code .addStatement ("throw new $T(ex)" , UncheckedIOException .class );
655
+ code .endControlFlow ();
656
+ return code .build ();
657
+ }
658
+
659
+ private CodeBlock generatePropertySourceDescriptorCode (PropertySourceDescriptor descriptor ) {
660
+ CodeBlock .Builder code = CodeBlock .builder ();
661
+ code .add ("new $T(" , PropertySourceDescriptor .class );
662
+ CodeBlock values = descriptor .locations ().stream ()
663
+ .map (value -> CodeBlock .of ("$S" , value )).collect (CodeBlock .joining (", " ));
664
+ if (descriptor .name () == null && descriptor .propertySourceFactory () == null
665
+ && descriptor .encoding () == null && !descriptor .ignoreResourceNotFound ()) {
666
+ code .add ("$L)" , values );
667
+ }
668
+ else {
669
+ code .add ("$T.of($L), " , List .class , values );
670
+ handleNull (code , descriptor .name (), () -> code .add ("$S, " , descriptor .name ()));
671
+ handleNull (code , descriptor .propertySourceFactory (),
672
+ () -> code .add ("$T.class, " , descriptor .propertySourceFactory ()));
673
+ handleNull (code , descriptor .encoding (), () -> code .add ("$S, " , descriptor .encoding ()));
674
+ code .add ("$L" , descriptor .ignoreResourceNotFound ());
675
+ code .add (")" );
676
+ }
677
+ return code .build ();
678
+ }
679
+
680
+ private void handleNull (CodeBlock .Builder code , @ Nullable Object value , Runnable nonNull ) {
681
+ if (value == null ) {
682
+ code .add ("null" );
683
+ }
684
+ else {
685
+ nonNull .run ();
686
+ }
687
+ }
688
+
689
+ }
690
+
588
691
}
0 commit comments