0
# Environment and Configuration
1
2
Spring Core provides a comprehensive environment abstraction that manages application properties, profiles, and configuration from various sources. This system enables flexible configuration management across different deployment environments.
3
4
## Environment Interface
5
6
The `Environment` interface provides the main abstraction for the runtime environment and application properties.
7
8
**Environment Interface**
9
```java { .api }
10
public interface Environment extends PropertyResolver {
11
String[] getActiveProfiles();
12
String[] getDefaultProfiles();
13
14
@Deprecated
15
boolean acceptsProfiles(String... profiles);
16
boolean acceptsProfiles(Profiles profiles);
17
}
18
19
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
20
void setActiveProfiles(String... profiles);
21
void addActiveProfile(String profile);
22
void setDefaultProfiles(String... profiles);
23
24
MutablePropertySources getPropertySources();
25
Map<String, Object> getSystemProperties();
26
Map<String, Object> getSystemEnvironment();
27
28
void merge(ConfigurableEnvironment parent);
29
}
30
```
31
32
**Standard Environment Implementation**
33
```java { .api }
34
public class StandardEnvironment extends AbstractEnvironment {
35
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
36
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
37
38
public StandardEnvironment();
39
40
@Override
41
protected void customizePropertySources(MutablePropertySources propertySources);
42
}
43
44
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
45
public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";
46
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
47
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
48
49
protected final Log logger = LogFactory.getLog(getClass());
50
private final Set<String> activeProfiles = new LinkedHashSet<>();
51
private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());
52
private final MutablePropertySources propertySources = new MutablePropertySources();
53
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
54
55
public AbstractEnvironment();
56
57
protected void customizePropertySources(MutablePropertySources propertySources);
58
protected Set<String> getReservedDefaultProfiles();
59
protected boolean isProfileActive(String profile);
60
61
@Override
62
public String[] getActiveProfiles();
63
@Override
64
public void setActiveProfiles(String... profiles);
65
@Override
66
public void addActiveProfile(String profile);
67
68
@Override
69
public String[] getDefaultProfiles();
70
@Override
71
public void setDefaultProfiles(String... profiles);
72
73
@Override
74
public boolean acceptsProfiles(Profiles profiles);
75
76
@Override
77
public MutablePropertySources getPropertySources();
78
}
79
```
80
81
**Usage Examples**
82
```java
83
// Basic environment usage
84
Environment env = new StandardEnvironment();
85
86
// Check active profiles
87
String[] activeProfiles = env.getActiveProfiles();
88
boolean isProduction = env.acceptsProfiles(Profiles.of("production"));
89
boolean isDevelopment = env.acceptsProfiles(Profiles.of("development"));
90
91
// Complex profile expressions
92
boolean isCloudOrDocker = env.acceptsProfiles(Profiles.of("cloud | docker"));
93
boolean isNotTest = env.acceptsProfiles(Profiles.of("!test"));
94
95
// Configure environment programmatically
96
ConfigurableEnvironment configurableEnv = new StandardEnvironment();
97
configurableEnv.setActiveProfiles("production", "cloud");
98
configurableEnv.addActiveProfile("monitoring");
99
100
// Access properties
101
String serverPort = env.getProperty("server.port", "8080");
102
Integer maxConnections = env.getProperty("server.max-connections", Integer.class, 100);
103
```
104
105
## Property Resolution
106
107
The property resolver system provides flexible property access with placeholder resolution and type conversion.
108
109
**PropertyResolver Interface**
110
```java { .api }
111
public interface PropertyResolver {
112
boolean containsProperty(String key);
113
String getProperty(String key);
114
String getProperty(String key, String defaultValue);
115
<T> T getProperty(String key, Class<T> targetType);
116
<T> T getProperty(String key, Class<T> targetType, T defaultValue);
117
118
String getRequiredProperty(String key) throws IllegalStateException;
119
<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;
120
121
String resolvePlaceholders(String text);
122
String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
123
}
124
125
public interface ConfigurablePropertyResolver extends PropertyResolver {
126
ConfigurableConversionService getConversionService();
127
void setConversionService(ConfigurableConversionService conversionService);
128
129
void setPlaceholderPrefix(String placeholderPrefix);
130
void setPlaceholderSuffix(String placeholderSuffix);
131
void setValueSeparator(String valueSeparator);
132
133
void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders);
134
void setRequiredProperties(String... requiredProperties);
135
void validateRequiredProperties() throws MissingRequiredPropertiesException;
136
}
137
```
138
139
**PropertySourcesPropertyResolver**
140
```java { .api }
141
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
142
public PropertySourcesPropertyResolver(PropertySources propertySources);
143
144
@Override
145
public boolean containsProperty(String key);
146
@Override
147
public String getProperty(String key);
148
@Override
149
public <T> T getProperty(String key, Class<T> targetType);
150
151
protected <T> T getProperty(String key, Class<T> targetType, boolean resolveNestedPlaceholders);
152
protected PropertySource<?> findPropertySource(String key);
153
}
154
```
155
156
**Usage Examples**
157
```java
158
// Property resolution with type conversion
159
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
160
161
// Basic property access
162
String appName = resolver.getProperty("app.name", "MyApp");
163
Integer port = resolver.getProperty("server.port", Integer.class, 8080);
164
Boolean enableSsl = resolver.getProperty("security.ssl.enabled", Boolean.class, false);
165
166
// Required properties (throw exception if missing)
167
String dbUrl = resolver.getRequiredProperty("database.url");
168
Integer maxPoolSize = resolver.getRequiredProperty("database.pool.max-size", Integer.class);
169
170
// Placeholder resolution
171
String template = "App ${app.name} running on port ${server.port}";
172
String resolved = resolver.resolvePlaceholders(template);
173
// Result: "App MyApp running on port 8080"
174
175
// Configure resolver
176
ConfigurablePropertyResolver configurable = new PropertySourcesPropertyResolver(propertySources);
177
configurable.setPlaceholderPrefix("#{");
178
configurable.setPlaceholderSuffix("}");
179
configurable.setValueSeparator(":");
180
configurable.setIgnoreUnresolvableNestedPlaceholders(true);
181
182
// Set required properties for validation
183
configurable.setRequiredProperties("database.url", "app.secret");
184
try {
185
configurable.validateRequiredProperties();
186
} catch (MissingRequiredPropertiesException ex) {
187
// Handle missing required properties
188
}
189
```
190
191
## Property Sources
192
193
Property sources provide the actual property values from various sources like files, environment variables, and system properties.
194
195
**PropertySource Classes**
196
```java { .api }
197
public abstract class PropertySource<T> {
198
protected final String name;
199
protected final T source;
200
201
public PropertySource(String name, T source);
202
public PropertySource(String name);
203
204
public String getName();
205
public T getSource();
206
public boolean containsProperty(String name);
207
public abstract Object getProperty(String name);
208
209
@Override
210
public boolean equals(Object other);
211
@Override
212
public int hashCode();
213
@Override
214
public String toString();
215
216
public static PropertySource<?> named(String name);
217
}
218
219
public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {
220
public MapPropertySource(String name, Map<String, Object> source);
221
222
@Override
223
public Object getProperty(String name);
224
@Override
225
public boolean containsProperty(String name);
226
@Override
227
public String[] getPropertyNames();
228
}
229
230
public class SystemEnvironmentPropertySource extends MapPropertySource {
231
public SystemEnvironmentPropertySource(String name, Map<String, Object> source);
232
233
@Override
234
public boolean containsProperty(String name);
235
@Override
236
public Object getProperty(String name);
237
238
protected boolean isSecurityManagerPresent();
239
protected String resolvePropertyName(String name);
240
}
241
242
public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
243
public EnumerablePropertySource(String name, T source);
244
public EnumerablePropertySource(String name);
245
246
@Override
247
public boolean containsProperty(String name);
248
public abstract String[] getPropertyNames();
249
}
250
```
251
252
**PropertySources Container**
253
```java { .api }
254
public interface PropertySources extends Iterable<PropertySource<?>> {
255
default Stream<PropertySource<?>> stream();
256
boolean contains(String name);
257
PropertySource<?> get(String name);
258
}
259
260
public class MutablePropertySources implements PropertySources {
261
public MutablePropertySources();
262
public MutablePropertySources(PropertySources propertySources);
263
264
@Override
265
public Iterator<PropertySource<?>> iterator();
266
@Override
267
public Spliterator<PropertySource<?>> spliterator();
268
@Override
269
public Stream<PropertySource<?>> stream();
270
@Override
271
public boolean contains(String name);
272
@Override
273
public PropertySource<?> get(String name);
274
275
public void addFirst(PropertySource<?> propertySource);
276
public void addLast(PropertySource<?> propertySource);
277
public void addBefore(String relativePropertySourceName, PropertySource<?> propertySource);
278
public void addAfter(String relativePropertySourceName, PropertySource<?> propertySource);
279
280
public int precedenceOf(PropertySource<?> propertySource);
281
public PropertySource<?> remove(String name);
282
public void replace(String name, PropertySource<?> propertySource);
283
284
public int size();
285
@Override
286
public String toString();
287
}
288
```
289
290
**Usage Examples**
291
```java
292
// Create property sources from various sources
293
Map<String, Object> appProps = new HashMap<>();
294
appProps.put("app.name", "MyApplication");
295
appProps.put("app.version", "1.0.0");
296
PropertySource<?> appPropertySource = new MapPropertySource("applicationProperties", appProps);
297
298
// System environment and properties
299
PropertySource<?> systemEnvSource = new SystemEnvironmentPropertySource(
300
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
301
System.getenv()
302
);
303
304
PropertySource<?> systemPropsSource = new PropertiesPropertySource(
305
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME,
306
System.getProperties()
307
);
308
309
// Manage property source precedence
310
MutablePropertySources propertySources = new MutablePropertySources();
311
propertySources.addFirst(appPropertySource); // Highest priority
312
propertySources.addLast(systemPropsSource); // Lowest priority
313
propertySources.addAfter("applicationProperties", systemEnvSource);
314
315
// Access through property resolver
316
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
317
String appName = resolver.getProperty("app.name"); // "MyApplication"
318
319
// Property source operations
320
boolean hasAppProps = propertySources.contains("applicationProperties");
321
PropertySource<?> appSource = propertySources.get("applicationProperties");
322
int precedence = propertySources.precedenceOf(appSource); // 0 (highest)
323
324
// Replace property source
325
Map<String, Object> newProps = new HashMap<>(appProps);
326
newProps.put("app.version", "2.0.0");
327
PropertySource<?> updatedSource = new MapPropertySource("applicationProperties", newProps);
328
propertySources.replace("applicationProperties", updatedSource);
329
```
330
331
## Profile Support
332
333
Spring provides sophisticated profile support for environment-specific configuration.
334
335
**Profiles Interface**
336
```java { .api }
337
public interface Profiles {
338
boolean matches(Predicate<String> activeProfiles);
339
340
static Profiles of(String... profiles);
341
}
342
343
class ProfilesParser {
344
static Profiles parse(String... expressions);
345
}
346
```
347
348
**Profile Expression Language**
349
```java
350
// Profile expressions support logical operators
351
Profiles production = Profiles.of("production");
352
Profiles cloudOrDocker = Profiles.of("cloud | docker");
353
Profiles notTest = Profiles.of("!test");
354
Profiles complexExpr = Profiles.of("(cloud | docker) & !test");
355
```
356
357
**Usage Examples**
358
```java
359
// Profile-based configuration
360
ConfigurableEnvironment env = new StandardEnvironment();
361
362
// Set profiles programmatically
363
env.setActiveProfiles("development", "debug");
364
env.addActiveProfile("local");
365
366
// Or via system properties
367
System.setProperty("spring.profiles.active", "production,cloud");
368
369
// Check profile conditions
370
boolean isDevEnvironment = env.acceptsProfiles(Profiles.of("development"));
371
boolean isCloudDeployment = env.acceptsProfiles(Profiles.of("cloud | docker"));
372
boolean isNotTesting = env.acceptsProfiles(Profiles.of("!test"));
373
374
// Complex profile logic in configuration
375
@Configuration
376
@Profile("production & !development")
377
public class ProductionConfig {
378
379
@Bean
380
@Profile("cloud | docker")
381
public DataSource cloudDataSource() {
382
// Cloud-specific datasource
383
}
384
385
@Bean
386
@Profile("!cloud")
387
public DataSource localDataSource() {
388
// Local datasource
389
}
390
}
391
392
// Conditional bean creation based on profiles
393
@Component
394
public class EnvironmentAwareService {
395
396
@Autowired
397
public EnvironmentAwareService(Environment env) {
398
if (env.acceptsProfiles(Profiles.of("development"))) {
399
// Development-specific initialization
400
} else if (env.acceptsProfiles(Profiles.of("production"))) {
401
// Production-specific initialization
402
}
403
}
404
}
405
```
406
407
## Property Placeholder Resolution
408
409
**PropertyPlaceholderHelper**
410
```java { .api }
411
public class PropertyPlaceholderHelper {
412
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix);
413
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix,
414
String valueSeparator, boolean ignoreUnresolvablePlaceholders);
415
416
public String replacePlaceholders(String value, Properties properties);
417
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver);
418
419
protected String parseStringValue(String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders);
420
421
@FunctionalInterface
422
public interface PlaceholderResolver {
423
String resolvePlaceholder(String placeholderName);
424
}
425
}
426
```
427
428
**Usage Examples**
429
```java
430
// Custom placeholder resolution
431
PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}", ":", true);
432
433
// Simple properties-based resolution
434
Properties props = new Properties();
435
props.setProperty("server.host", "localhost");
436
props.setProperty("server.port", "8080");
437
438
String template = "Server running at ${server.host}:${server.port}";
439
String resolved = helper.replacePlaceholders(template, props);
440
// Result: "Server running at localhost:8080"
441
442
// Custom placeholder resolver
443
PlaceholderResolver resolver = placeholderName -> {
444
switch (placeholderName) {
445
case "timestamp": return String.valueOf(System.currentTimeMillis());
446
case "random": return String.valueOf(Math.random());
447
default: return null;
448
}
449
};
450
451
String dynamicTemplate = "Generated at ${timestamp} with random ${random}";
452
String dynamicResolved = helper.replacePlaceholders(dynamicTemplate, resolver);
453
454
// Default value support
455
String withDefaults = "Host: ${server.host:localhost}, Port: ${server.port:8080}";
456
String resolvedWithDefaults = helper.replacePlaceholders(withDefaults, props);
457
```
458
459
## Environment Profiles Utility
460
461
**ProfilesParser and Profile Expression Support**
462
```java { .api }
463
final class Profiles {
464
private final String[] expressions;
465
466
private Profiles(String[] expressions);
467
468
public static Profiles of(String... profiles);
469
public boolean matches(Predicate<String> activeProfiles);
470
471
private static class ParsedProfiles implements Profiles {
472
private final Set<ProfileExpression> expressions;
473
474
ParsedProfiles(String... expressions);
475
476
@Override
477
public boolean matches(Predicate<String> activeProfiles);
478
}
479
}
480
```
481
482
**Advanced Environment Configuration**
483
```java { .api }
484
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
485
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
486
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
487
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
488
489
@Override
490
protected void customizePropertySources(MutablePropertySources propertySources);
491
492
@Override
493
public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig);
494
}
495
```
496
497
**Usage Examples**
498
```java
499
// Advanced profile expressions
500
Environment env = new StandardEnvironment();
501
502
// Logical AND
503
boolean isProdAndCloud = env.acceptsProfiles(Profiles.of("production & cloud"));
504
505
// Logical OR
506
boolean isDevOrTest = env.acceptsProfiles(Profiles.of("development | test"));
507
508
// Negation
509
boolean isNotProduction = env.acceptsProfiles(Profiles.of("!production"));
510
511
// Complex expressions with grouping
512
boolean complexCondition = env.acceptsProfiles(Profiles.of("(cloud | docker) & !test & production"));
513
514
// Multiple profile checks
515
String[] activeProfiles = env.getActiveProfiles();
516
boolean hasAnyActiveProfile = Arrays.stream(activeProfiles).anyMatch(profile ->
517
env.acceptsProfiles(Profiles.of(profile))
518
);
519
520
// Environment merging for hierarchical configurations
521
ConfigurableEnvironment child = new StandardEnvironment();
522
child.setActiveProfiles("development");
523
524
ConfigurableEnvironment parent = new StandardEnvironment();
525
parent.setActiveProfiles("base");
526
parent.getPropertySources().addFirst(new MapPropertySource("parentProps",
527
Map.of("parent.property", "parent-value")));
528
529
child.merge(parent);
530
// Child now has access to parent's property sources and profiles
531
```
532
533
This environment and configuration system provides the foundation for Spring's flexible, profile-aware configuration management, enabling applications to adapt their behavior based on deployment context while maintaining clean separation of concerns.