0
# Configuration Management
1
2
Spring Boot's configuration management system provides type-safe property binding, validation, and flexible property source handling. It enables external configuration through properties files, environment variables, command-line arguments, and more.
3
4
## Capabilities
5
6
### Configuration Properties Annotations
7
8
Core annotations for binding external configuration to Java objects.
9
10
```java { .api }
11
/**
12
* Annotation for externalized configuration. Binds and validates external
13
* configuration (e.g. from properties files)
14
*/
15
@Target({ElementType.TYPE, ElementType.METHOD})
16
@Retention(RetentionPolicy.RUNTIME)
17
@Documented
18
public @interface ConfigurationProperties {
19
20
/**
21
* The name prefix of the properties that are valid to bind to this object.
22
* Synonym for prefix(). A valid prefix is defined by one or more valid
23
* {@code ConfigurationPropertyName} segments separated by "."
24
* @return the name prefix of the properties to bind
25
*/
26
@AliasFor("prefix")
27
String value() default "";
28
29
/**
30
* The name prefix of the properties that are valid to bind to this object.
31
* Synonym for value(). A valid prefix is defined by one or more valid
32
* {@code ConfigurationPropertyName} segments separated by "."
33
* @return the name prefix of the properties to bind
34
*/
35
@AliasFor("value")
36
String prefix() default "";
37
38
/**
39
* Flag to indicate that when binding to this object invalid fields should be ignored.
40
* Invalid means invalid according to the binder that is used, and usually this means
41
* fields of the wrong type (or that cannot be coerced into the correct type).
42
* @return the flag value (default false)
43
*/
44
boolean ignoreInvalidFields() default false;
45
46
/**
47
* Flag to indicate that when binding to this object fields with periods in their
48
* names should be ignored.
49
* @return the flag value (default true)
50
*/
51
boolean ignoreUnknownFields() default true;
52
}
53
54
/**
55
* Enable support for ConfigurationProperties annotated classes
56
*/
57
@Target(ElementType.TYPE)
58
@Retention(RetentionPolicy.RUNTIME)
59
@Documented
60
@Import(EnableConfigurationPropertiesRegistrar.class)
61
public @interface EnableConfigurationProperties {
62
63
/**
64
* The configuration properties classes to register
65
* @return the classes to register
66
*/
67
Class<?>[] value() default {};
68
}
69
70
/**
71
* Scan for ConfigurationProperties annotated classes
72
*/
73
@Target(ElementType.TYPE)
74
@Retention(RetentionPolicy.RUNTIME)
75
@Documented
76
@Import(ConfigurationPropertiesScanRegistrar.class)
77
public @interface ConfigurationPropertiesScan {
78
79
/**
80
* Alias for the basePackages() attribute. Allows for more concise annotation
81
* declarations e.g.: {@code @ConfigurationPropertiesScan("org.my.pkg")}
82
* instead of {@code @ConfigurationPropertiesScan(basePackages="org.my.pkg")}
83
* @return the base packages to scan
84
*/
85
@AliasFor("basePackages")
86
String[] value() default {};
87
88
/**
89
* Base packages to scan for annotated configuration properties classes
90
* @return the base packages to scan
91
*/
92
@AliasFor("value")
93
String[] basePackages() default {};
94
95
/**
96
* Type-safe alternative to basePackages() for specifying the packages to scan
97
* @return classes that are in the base packages
98
*/
99
Class<?>[] basePackageClasses() default {};
100
}
101
102
/**
103
* Indicates that a field in a ConfigurationProperties object should be treated as
104
* if it were a nested type
105
*/
106
@Target({ElementType.FIELD, ElementType.METHOD})
107
@Retention(RetentionPolicy.RUNTIME)
108
@Documented
109
public @interface NestedConfigurationProperty {
110
}
111
112
/**
113
* Indicates that a getter in a ConfigurationProperties object is deprecated
114
*/
115
@Target({ElementType.METHOD})
116
@Retention(RetentionPolicy.RUNTIME)
117
@Documented
118
public @interface DeprecatedConfigurationProperty {
119
120
/**
121
* The reason for the deprecation
122
* @return the reason for the deprecation
123
*/
124
String reason() default "";
125
126
/**
127
* The replacement property that should be used instead
128
* @return the replacement property
129
*/
130
String replacement() default "";
131
}
132
```
133
134
**Usage Examples:**
135
136
```java
137
// Basic configuration properties class
138
@ConfigurationProperties(prefix = "app")
139
@Component
140
public class AppProperties {
141
142
private String name = "My Application";
143
private Duration timeout = Duration.ofSeconds(30);
144
private final Security security = new Security();
145
146
// Getters and setters
147
public String getName() { return name; }
148
public void setName(String name) { this.name = name; }
149
150
public Duration getTimeout() { return timeout; }
151
public void setTimeout(Duration timeout) { this.timeout = timeout; }
152
153
@NestedConfigurationProperty
154
public Security getSecurity() { return security; }
155
156
public static class Security {
157
private String username;
158
private String password;
159
private List<String> roles = new ArrayList<>();
160
161
// Getters and setters
162
public String getUsername() { return username; }
163
public void setUsername(String username) { this.username = username; }
164
165
public String getPassword() { return password; }
166
public void setPassword(String password) { this.password = password; }
167
168
public List<String> getRoles() { return roles; }
169
public void setRoles(List<String> roles) { this.roles = roles; }
170
}
171
}
172
173
// Enable configuration properties
174
@Configuration
175
@EnableConfigurationProperties(AppProperties.class)
176
public class AppConfiguration {
177
178
@Autowired
179
private AppProperties properties;
180
181
@Bean
182
public MyService myService() {
183
return new MyService(properties.getName(), properties.getTimeout());
184
}
185
}
186
187
// Scan for configuration properties
188
@SpringBootApplication
189
@ConfigurationPropertiesScan("com.example.config")
190
public class Application {
191
public static void main(String[] args) {
192
SpringApplication.run(Application.class, args);
193
}
194
}
195
```
196
197
### Property Binding Core
198
199
Core classes for binding configuration properties with type safety and validation.
200
201
```java { .api }
202
/**
203
* A container object to bind from some ConfigurationPropertySources
204
*/
205
public class Binder {
206
207
/**
208
* Create a new Binder instance for the specified sources
209
* @param sources the configuration property sources
210
*/
211
public Binder(ConfigurationPropertySource... sources);
212
213
/**
214
* Create a new Binder instance for the specified sources
215
* @param sources the configuration property sources
216
* @param placeholdersResolver strategy to resolve any property placeholders
217
* @param conversionService the conversion service to convert bound properties
218
* @param propertyEditorInitializer used to configure property editors that can
219
* convert values
220
*/
221
public Binder(Iterable<ConfigurationPropertySource> sources,
222
PlaceholdersResolver placeholdersResolver,
223
ConversionService conversionService,
224
Consumer<PropertyEditorRegistry> propertyEditorInitializer);
225
226
/**
227
* Return a binder instance that is backed by the specified Environment and uses
228
* all qualifier and conversion rules found in the environment
229
* @param environment the environment (must not be null)
230
* @return a binder instance
231
*/
232
public static Binder get(Environment environment);
233
234
/**
235
* Bind the specified target Class using this binder's property sources
236
* @param name the configuration property name to bind
237
* @param target the target class
238
* @return the binding result (never null)
239
*/
240
public <T> BindResult<T> bind(String name, Class<T> target);
241
242
/**
243
* Bind the specified target Bindable using this binder's property sources
244
* @param name the configuration property name to bind
245
* @param target the target bindable
246
* @return the binding result (never null)
247
*/
248
public <T> BindResult<T> bind(String name, Bindable<T> target);
249
250
/**
251
* Bind the specified target Bindable using this binder's property sources
252
* @param name the configuration property name to bind
253
* @param target the target bindable
254
* @return the binding result (never null)
255
*/
256
public <T> BindResult<T> bind(ConfigurationPropertyName name, Bindable<T> target);
257
258
/**
259
* Bind the specified target Bindable using this binder's property sources or
260
* create a new instance using the type of the Bindable if the result of the
261
* binding is null
262
* @param name the configuration property name to bind
263
* @param target the target bindable
264
* @return the bound or created object (never null)
265
*/
266
public <T> T bindOrCreate(String name, Bindable<T> target);
267
}
268
269
/**
270
* A source of ConfigurationProperty objects
271
*/
272
public interface ConfigurationPropertySource {
273
274
/**
275
* Return a single ConfigurationProperty from the source or null if no
276
* property can be found
277
* @param name the name of the property (must not be null)
278
* @return the associated object or null
279
*/
280
ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name);
281
282
/**
283
* Return a variant of this source that supports name aliases
284
* @param aliases the name aliases
285
* @return a new source that supports name aliases
286
*/
287
default ConfigurationPropertySource withAliases(ConfigurationPropertyNameAliases aliases) {
288
return new AliasedConfigurationPropertySource(this, aliases);
289
}
290
}
291
292
/**
293
* A configuration property name
294
*/
295
public final class ConfigurationPropertyName implements Comparable<ConfigurationPropertyName> {
296
297
/**
298
* Create a ConfigurationPropertyName from the specified string
299
* @param name the source name (must not be null)
300
* @return a ConfigurationPropertyName instance or null if the name is not valid
301
*/
302
public static ConfigurationPropertyName of(String name);
303
304
/**
305
* Return if the given string is a valid ConfigurationPropertyName
306
* @param name the name to check
307
* @return true if the name is valid
308
*/
309
public static boolean isValid(CharSequence name);
310
311
/**
312
* Return a new ConfigurationPropertyName by appending the given elements
313
* @param elements the elements to append
314
* @return a new ConfigurationPropertyName
315
*/
316
public ConfigurationPropertyName append(String elements);
317
318
/**
319
* Return the number of elements that make up the name
320
* @return the number of elements
321
*/
322
public int getNumberOfElements();
323
324
/**
325
* Return an element from the name
326
* @param elementIndex the element index
327
* @return the element
328
*/
329
public String getElement(int elementIndex, Form form);
330
}
331
```
332
333
**Usage Examples:**
334
335
```java
336
@Service
337
public class ConfigurationService {
338
339
private final Binder binder;
340
341
public ConfigurationService(Environment environment) {
342
this.binder = Binder.get(environment);
343
}
344
345
public <T> T bindConfiguration(String prefix, Class<T> configClass) {
346
return binder.bind(prefix, configClass)
347
.orElseThrow(() -> new IllegalStateException("Could not bind " + prefix));
348
}
349
350
public void validateConfiguration() {
351
// Bind database configuration
352
DatabaseConfig dbConfig = bindConfiguration("app.database", DatabaseConfig.class);
353
354
// Bind cache configuration with default fallback
355
CacheConfig cacheConfig = binder.bind("app.cache", Bindable.of(CacheConfig.class))
356
.orElse(new CacheConfig()); // Use default if not configured
357
}
358
}
359
```
360
361
### Constructor and Default Value Binding
362
363
Annotations for constructor-based binding and default values.
364
365
```java { .api }
366
/**
367
* Annotation that can be used to indicate which constructor to use when binding
368
* configuration properties
369
*/
370
@Target({ElementType.CONSTRUCTOR, ElementType.TYPE})
371
@Retention(RetentionPolicy.RUNTIME)
372
@Documented
373
public @interface ConstructorBinding {
374
}
375
376
/**
377
* Annotation that can be used to specify a default value when binding to an
378
* immutable property
379
*/
380
@Target({ElementType.PARAMETER})
381
@Retention(RetentionPolicy.RUNTIME)
382
@Documented
383
public @interface DefaultValue {
384
385
/**
386
* The default value of the property
387
* @return the default values
388
*/
389
String[] value();
390
}
391
392
/**
393
* Annotation that can be used to specify the name when binding to an immutable property
394
*/
395
@Target({ElementType.PARAMETER})
396
@Retention(RetentionPolicy.RUNTIME)
397
@Documented
398
public @interface Name {
399
400
/**
401
* The name of the property to bind to
402
* @return the property name
403
*/
404
String value();
405
}
406
```
407
408
**Usage Examples:**
409
410
```java
411
// Constructor-based binding for immutable configuration
412
@ConfigurationProperties("server")
413
@ConstructorBinding
414
public class ServerProperties {
415
416
private final String host;
417
private final int port;
418
private final Duration timeout;
419
private final List<String> allowedOrigins;
420
421
public ServerProperties(@Name("host") @DefaultValue("localhost") String host,
422
@Name("port") @DefaultValue("8080") int port,
423
@DefaultValue("30s") Duration timeout,
424
@Name("allowed-origins") List<String> allowedOrigins) {
425
this.host = host;
426
this.port = port;
427
this.timeout = timeout;
428
this.allowedOrigins = allowedOrigins != null ? allowedOrigins : Collections.emptyList();
429
}
430
431
public String getHost() { return host; }
432
public int getPort() { return port; }
433
public Duration getTimeout() { return timeout; }
434
public List<String> getAllowedOrigins() { return allowedOrigins; }
435
}
436
```
437
438
### Property Validation and Error Handling
439
440
Handlers for property binding validation and error management.
441
442
```java { .api }
443
/**
444
* Callback interface that can be used to handle additional logic during element binding
445
*/
446
public interface BindHandler {
447
448
/**
449
* Handle the start of a bind operation for the given name and target
450
* @param name the name of the element being bound
451
* @param target the item being bound
452
* @param context the bind context
453
* @return the bound value or null
454
*/
455
default <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {
456
return target;
457
}
458
459
/**
460
* Handle a successful bind of an element
461
* @param name the name of the element being bound
462
* @param target the item being bound
463
* @param context the bind context
464
* @param result the bound result (may be null)
465
* @return the actual result that should be used (may be null)
466
*/
467
default Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) {
468
return result;
469
}
470
471
/**
472
* Handle a bind failure
473
* @param name the name of the element being bound
474
* @param target the item being bound
475
* @param context the bind context
476
* @param error the bind error
477
* @return the bound value or null if no recovery is possible
478
*/
479
default Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Exception error)
480
throws Exception {
481
throw error;
482
}
483
}
484
485
/**
486
* BindHandler to enforce that all configuration properties are consumed when binding
487
*/
488
public class NoUnboundElementsBindHandler implements BindHandler {
489
490
/**
491
* Create a new NoUnboundElementsBindHandler instance
492
*/
493
public NoUnboundElementsBindHandler();
494
495
/**
496
* Create a new NoUnboundElementsBindHandler that delegates to the specified parent handler
497
* @param parent the parent handler
498
*/
499
public NoUnboundElementsBindHandler(BindHandler parent);
500
}
501
502
/**
503
* BindHandler that can be used to ignore binding errors
504
*/
505
public class IgnoreErrorsBindHandler implements BindHandler {
506
507
/**
508
* Create a new IgnoreErrorsBindHandler instance
509
*/
510
public IgnoreErrorsBindHandler();
511
512
/**
513
* Create a new IgnoreErrorsBindHandler that delegates to the specified parent handler
514
* @param parent the parent handler
515
*/
516
public IgnoreErrorsBindHandler(BindHandler parent);
517
}
518
519
/**
520
* BindHandler to apply JSR-303 style validation to bound results
521
*/
522
public class ValidationBindHandler implements BindHandler {
523
524
/**
525
* Create a new ValidationBindHandler using the default JSR-303 validator
526
*/
527
public ValidationBindHandler();
528
529
/**
530
* Create a new ValidationBindHandler using the given validator
531
* @param validator the validator to use
532
*/
533
public ValidationBindHandler(Validator validator);
534
}
535
```
536
537
### Property Mapping Utilities
538
539
Utilities for mapping and transforming properties during binding.
540
541
```java { .api }
542
/**
543
* Utility that can be used to map values from one object to another
544
*/
545
public final class PropertyMapper {
546
547
/**
548
* Return a new PropertyMapper instance
549
* @return new PropertyMapper instance
550
*/
551
public static PropertyMapper get();
552
553
/**
554
* Return a new PropertyMapper that will always apply non-null values when mapping
555
* @return new PropertyMapper that applies non-null values
556
*/
557
public PropertyMapper alwaysApplyingWhenNonNull();
558
559
/**
560
* Supply a source value that will be mapped
561
* @param value the value (may be null)
562
* @return a property source
563
*/
564
public <T> Source<T> from(T value);
565
566
/**
567
* Supply a source value from a supplier that will be mapped
568
* @param supplier the value supplier (may return null)
569
* @return a property source
570
*/
571
public <T> Source<T> from(Supplier<T> supplier);
572
573
/**
574
* A source that is in the process of being mapped
575
*/
576
public static final class Source<T> {
577
578
/**
579
* Apply a condition that must be met for the mapping to be applied
580
* @param condition the condition that must be met
581
* @return a filtered source
582
*/
583
public Source<T> when(Predicate<T> condition);
584
585
/**
586
* Apply the mapping when the value is not null
587
* @return a filtered source that won't map null values
588
*/
589
public Source<T> whenNonNull();
590
591
/**
592
* Apply the mapping using the given consumer
593
* @param consumer the consumer to apply the mapping
594
*/
595
public void to(Consumer<T> consumer);
596
597
/**
598
* Apply the mapping to the given setter
599
* @param setter the setter to apply
600
*/
601
public <R> void to(Function<T, R> mapper, Consumer<R> consumer);
602
}
603
}
604
```
605
606
**Usage Examples:**
607
608
```java
609
@Component
610
public class ConfigurationMapper {
611
612
public void configureHttpClient(HttpClientProperties source, HttpClient.Builder target) {
613
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
614
615
map.from(source.getTimeout()).to(target::timeout);
616
map.from(source.getMaxConnections()).to(target::maxConnections);
617
map.from(source.isFollowRedirects()).to(target::followRedirects);
618
map.from(source.getProxyHost()).whenNonNull().to(target::proxy);
619
620
// Conditional mapping
621
map.from(source.getRetryCount())
622
.when(count -> count > 0)
623
.to(target::retryPolicy);
624
}
625
}
626
```
627
628
### Environment Post-Processing
629
630
Interface for post-processing the environment before application context refresh.
631
632
```java { .api }
633
/**
634
* Allows for customization of the application's Environment prior to the application
635
* context being refreshed
636
*/
637
@FunctionalInterface
638
public interface EnvironmentPostProcessor {
639
640
/**
641
* Post-process the given ConfigurableEnvironment after all property sources have been loaded
642
* @param environment the environment to post-process
643
* @param application the application to which the environment belongs
644
*/
645
void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);
646
}
647
648
/**
649
* Strategy interface for loading property sources from resources
650
*/
651
public interface PropertySourceLoader {
652
653
/**
654
* Returns the file extensions that this loader supports (excluding the '.')
655
* @return the file extensions
656
*/
657
String[] getFileExtensions();
658
659
/**
660
* Load the resource into one or more property sources
661
* @param name the root name of the property source. If multiple documents are loaded
662
* an additional suffix should be added to the name for each source loaded
663
* @param resource the resource to load
664
* @return a list property sources
665
* @throws IOException if the resource cannot be loaded
666
*/
667
List<PropertySource<?>> load(String name, Resource resource) throws IOException;
668
}
669
```
670
671
**Usage Examples:**
672
673
```java
674
// Custom environment post-processor
675
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {
676
677
@Override
678
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
679
// Add custom property sources based on environment conditions
680
if (environment.acceptsProfiles(Profiles.of("dev"))) {
681
Properties devProps = new Properties();
682
devProps.put("logging.level.com.example", "DEBUG");
683
devProps.put("spring.jpa.show-sql", "true");
684
685
PropertiesPropertySource devPropertySource = new PropertiesPropertySource("devProperties", devProps);
686
environment.getPropertySources().addLast(devPropertySource);
687
}
688
}
689
}
690
691
// Custom property source loader for YAML files
692
public class YamlPropertySourceLoader implements PropertySourceLoader {
693
694
@Override
695
public String[] getFileExtensions() {
696
return new String[]{"yml", "yaml"};
697
}
698
699
@Override
700
public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
701
if (resource.exists()) {
702
List<PropertySource<?>> propertySources = new ArrayList<>();
703
// Load YAML and convert to PropertySource
704
// Implementation details...
705
return propertySources;
706
}
707
return Collections.emptyList();
708
}
709
}
710
711
// Register in META-INF/spring.factories:
712
// org.springframework.boot.env.EnvironmentPostProcessor=\
713
// com.example.CustomEnvironmentPostProcessor
714
// org.springframework.boot.env.PropertySourceLoader=\
715
// com.example.YamlPropertySourceLoader
716
```
717
718
## Configuration Property Sources
719
720
```java { .api }
721
/**
722
* ConfigurationPropertySource backed by a Map
723
*/
724
public class MapConfigurationPropertySource implements IterableConfigurationPropertySource {
725
726
/**
727
* Create a new MapConfigurationPropertySource instance
728
* @param name the name of the property source
729
* @param source the underlying map source
730
*/
731
public MapConfigurationPropertySource(String name, Map<?, ?> source);
732
733
/**
734
* Convenience method to create a MapConfigurationPropertySource from a Map with
735
* relaxed names support
736
* @param source the source map
737
* @return the property source
738
*/
739
public static MapConfigurationPropertySource from(Map<String, Object> source);
740
}
741
```