1
1
/*
2
- * Copyright 2012-2023 the original author or authors.
2
+ * Copyright 2012-2024 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.
16
16
17
17
package org .springframework .boot .env ;
18
18
19
+ import java .util .Arrays ;
19
20
import java .util .List ;
20
21
import java .util .function .Function ;
21
22
23
+ import javax .lang .model .element .Modifier ;
24
+
25
+ import org .springframework .aot .AotDetector ;
26
+ import org .springframework .aot .generate .GeneratedClass ;
27
+ import org .springframework .aot .generate .GenerationContext ;
28
+ import org .springframework .beans .BeanInstantiationException ;
29
+ import org .springframework .beans .BeanUtils ;
30
+ import org .springframework .beans .factory .aot .BeanFactoryInitializationAotContribution ;
31
+ import org .springframework .beans .factory .aot .BeanFactoryInitializationAotProcessor ;
32
+ import org .springframework .beans .factory .aot .BeanFactoryInitializationCode ;
33
+ import org .springframework .beans .factory .config .ConfigurableListableBeanFactory ;
22
34
import org .springframework .boot .ConfigurableBootstrapContext ;
23
35
import org .springframework .boot .SpringApplication ;
24
36
import org .springframework .boot .context .event .ApplicationEnvironmentPreparedEvent ;
25
37
import org .springframework .boot .context .event .ApplicationFailedEvent ;
26
38
import org .springframework .boot .context .event .ApplicationPreparedEvent ;
27
39
import org .springframework .boot .logging .DeferredLogs ;
28
40
import org .springframework .context .ApplicationEvent ;
41
+ import org .springframework .context .ConfigurableApplicationContext ;
29
42
import org .springframework .context .event .SmartApplicationListener ;
30
43
import org .springframework .core .Ordered ;
31
44
import org .springframework .core .env .ConfigurableEnvironment ;
45
+ import org .springframework .core .env .Environment ;
32
46
import org .springframework .core .io .ResourceLoader ;
47
+ import org .springframework .javapoet .CodeBlock ;
48
+ import org .springframework .util .Assert ;
49
+ import org .springframework .util .ClassUtils ;
50
+ import org .springframework .util .ObjectUtils ;
33
51
34
52
/**
35
53
* {@link SmartApplicationListener} used to trigger {@link EnvironmentPostProcessor
36
54
* EnvironmentPostProcessors} registered in the {@code spring.factories} file.
37
55
*
38
56
* @author Phillip Webb
57
+ * @author Stephane Nicoll
39
58
* @since 2.4.0
40
59
*/
41
60
public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener , Ordered {
42
61
62
+ private static final String AOT_FEATURE_NAME = "EnvironmentPostProcessor" ;
63
+
43
64
/**
44
65
* The default order for the processor.
45
66
*/
@@ -104,8 +125,10 @@ public void onApplicationEvent(ApplicationEvent event) {
104
125
private void onApplicationEnvironmentPreparedEvent (ApplicationEnvironmentPreparedEvent event ) {
105
126
ConfigurableEnvironment environment = event .getEnvironment ();
106
127
SpringApplication application = event .getSpringApplication ();
107
- for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors (application .getResourceLoader (),
108
- event .getBootstrapContext ())) {
128
+ List <EnvironmentPostProcessor > postProcessors = getEnvironmentPostProcessors (application .getResourceLoader (),
129
+ event .getBootstrapContext ());
130
+ addAotGeneratedEnvironmentPostProcessorIfNecessary (postProcessors , application );
131
+ for (EnvironmentPostProcessor postProcessor : postProcessors ) {
109
132
postProcessor .postProcessEnvironment (environment , application );
110
133
}
111
134
}
@@ -129,6 +152,32 @@ List<EnvironmentPostProcessor> getEnvironmentPostProcessors(ResourceLoader resou
129
152
return postProcessorsFactory .getEnvironmentPostProcessors (this .deferredLogs , bootstrapContext );
130
153
}
131
154
155
+ private void addAotGeneratedEnvironmentPostProcessorIfNecessary (List <EnvironmentPostProcessor > postProcessors ,
156
+ SpringApplication springApplication ) {
157
+ if (AotDetector .useGeneratedArtifacts ()) {
158
+ ClassLoader classLoader = (springApplication .getResourceLoader () != null )
159
+ ? springApplication .getResourceLoader ().getClassLoader () : null ;
160
+ String postProcessorClassName = springApplication .getMainApplicationClass ().getName () + "__"
161
+ + AOT_FEATURE_NAME ;
162
+ if (ClassUtils .isPresent (postProcessorClassName , classLoader )) {
163
+ postProcessors .add (0 , instantiateEnvironmentPostProcessor (postProcessorClassName , classLoader ));
164
+ }
165
+ }
166
+ }
167
+
168
+ private EnvironmentPostProcessor instantiateEnvironmentPostProcessor (String postProcessorClassName ,
169
+ ClassLoader classLoader ) {
170
+ try {
171
+ Class <?> initializerClass = ClassUtils .resolveClassName (postProcessorClassName , classLoader );
172
+ Assert .isAssignable (EnvironmentPostProcessor .class , initializerClass );
173
+ return (EnvironmentPostProcessor ) BeanUtils .instantiateClass (initializerClass );
174
+ }
175
+ catch (BeanInstantiationException ex ) {
176
+ throw new IllegalArgumentException (
177
+ "Failed to instantiate EnvironmentPostProcessor: " + postProcessorClassName , ex );
178
+ }
179
+ }
180
+
132
181
@ Override
133
182
public int getOrder () {
134
183
return this .order ;
@@ -138,4 +187,63 @@ public void setOrder(int order) {
138
187
this .order = order ;
139
188
}
140
189
190
+ /**
191
+ * Contribute a {@code <Application>__EnvironmentPostProcessor} class that stores AOT
192
+ * optimizations.
193
+ */
194
+ static class EnvironmentBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor {
195
+
196
+ @ Override
197
+ public BeanFactoryInitializationAotContribution processAheadOfTime (
198
+ ConfigurableListableBeanFactory beanFactory ) {
199
+ Environment environment = beanFactory .getBean (ConfigurableApplicationContext .ENVIRONMENT_BEAN_NAME ,
200
+ Environment .class );
201
+ String [] activeProfiles = environment .getActiveProfiles ();
202
+ String [] defaultProfiles = environment .getDefaultProfiles ();
203
+ if (!ObjectUtils .isEmpty (activeProfiles ) && !Arrays .equals (activeProfiles , defaultProfiles )) {
204
+ return new EnvironmentAotContribution (activeProfiles );
205
+ }
206
+ return null ;
207
+ }
208
+
209
+ }
210
+
211
+ private static final class EnvironmentAotContribution implements BeanFactoryInitializationAotContribution {
212
+
213
+ private static final String ENVIRONMENT_VARIABLE = "environment" ;
214
+
215
+ private final String [] activeProfiles ;
216
+
217
+ private EnvironmentAotContribution (String [] activeProfiles ) {
218
+ this .activeProfiles = activeProfiles ;
219
+ }
220
+
221
+ @ Override
222
+ public void applyTo (GenerationContext generationContext ,
223
+ BeanFactoryInitializationCode beanFactoryInitializationCode ) {
224
+ GeneratedClass generatedClass = generationContext .getGeneratedClasses ()
225
+ .addForFeature (AOT_FEATURE_NAME , (type ) -> {
226
+ type .addModifiers (Modifier .PUBLIC );
227
+ type .addJavadoc ("Configure the environment with AOT optimizations." );
228
+ type .addSuperinterface (EnvironmentPostProcessor .class );
229
+ });
230
+ generatedClass .getMethods ().add ("postProcessEnvironment" , (method ) -> {
231
+ method .addModifiers (Modifier .PUBLIC );
232
+ method .addAnnotation (Override .class );
233
+ method .addParameter (ConfigurableEnvironment .class , ENVIRONMENT_VARIABLE );
234
+ method .addParameter (SpringApplication .class , "application" );
235
+ method .addCode (generateActiveProfilesInitializeCode ());
236
+ });
237
+ }
238
+
239
+ private CodeBlock generateActiveProfilesInitializeCode () {
240
+ CodeBlock .Builder code = CodeBlock .builder ();
241
+ for (String activeProfile : this .activeProfiles ) {
242
+ code .addStatement ("$L.addActiveProfile($S)" , ENVIRONMENT_VARIABLE , activeProfile );
243
+ }
244
+ return code .build ();
245
+ }
246
+
247
+ }
248
+
141
249
}
0 commit comments