0
# Conditional Configuration
1
2
Spring Boot's conditional configuration system provides sophisticated annotations that determine when auto-configurations should be applied based on various runtime conditions including classpath contents, bean presence, properties, and environment characteristics.
3
4
## Capabilities
5
6
### Class-Based Conditions
7
8
Conditional annotations that evaluate based on the presence or absence of classes on the classpath.
9
10
```java { .api }
11
/**
12
* Matches when all specified classes are present on the classpath
13
* Most commonly used conditional annotation in auto-configurations
14
*/
15
@Target({ElementType.TYPE, ElementType.METHOD})
16
@Retention(RetentionPolicy.RUNTIME)
17
@Documented
18
@Conditional(OnClassCondition.class)
19
public @interface ConditionalOnClass {
20
/**
21
* Classes that must be present on the classpath
22
* @return array of required classes
23
*/
24
Class<?>[] value() default {};
25
26
/**
27
* Class names that must be present (alternative to value for classes not on current classpath)
28
* @return array of required class names
29
*/
30
String[] name() default {};
31
}
32
33
/**
34
* Matches when none of the specified classes are present on the classpath
35
* Used to disable configurations when competing libraries are present
36
*/
37
@Target({ElementType.TYPE, ElementType.METHOD})
38
@Retention(RetentionPolicy.RUNTIME)
39
@Documented
40
@Conditional(OnClassCondition.class)
41
public @interface ConditionalOnMissingClass {
42
/**
43
* Classes that must not be present on the classpath
44
* @return array of classes that should be absent
45
*/
46
Class<?>[] value() default {};
47
48
/**
49
* Class names that must not be present
50
* @return array of class names that should be absent
51
*/
52
String[] name() default {};
53
}
54
```
55
56
**Usage Examples:**
57
58
```java
59
@AutoConfiguration
60
@ConditionalOnClass({DataSource.class, JdbcTemplate.class})
61
public class JdbcTemplateAutoConfiguration {
62
// Only applies when both DataSource and JdbcTemplate are on classpath
63
}
64
65
@AutoConfiguration
66
@ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper")
67
@ConditionalOnMissingClass("com.google.gson.Gson")
68
public class JacksonAutoConfiguration {
69
// Applies when Jackson is present but Gson is not
70
}
71
```
72
73
### Bean-Based Conditions
74
75
Conditional annotations that evaluate based on the presence, absence, or characteristics of beans in the application context.
76
77
```java { .api }
78
/**
79
* Matches when specified beans are present in the application context
80
* Useful for ensuring dependencies are available
81
*/
82
@Target({ElementType.TYPE, ElementType.METHOD})
83
@Retention(RetentionPolicy.RUNTIME)
84
@Documented
85
@Conditional(OnBeanCondition.class)
86
public @interface ConditionalOnBean {
87
/**
88
* Bean classes that must be present
89
* @return array of required bean classes
90
*/
91
Class<?>[] value() default {};
92
93
/**
94
* Bean type names that must be present
95
* @return array of required bean type names
96
*/
97
String[] type() default {};
98
99
/**
100
* Bean names that must be present
101
* @return array of required bean names
102
*/
103
String[] name() default {};
104
105
/**
106
* Strategy for searching beans
107
* @return search strategy
108
*/
109
SearchStrategy search() default SearchStrategy.ALL;
110
111
/**
112
* Additional annotation that must be present on the beans
113
* @return annotation class
114
*/
115
Class<? extends Annotation> annotation() default Annotation.class;
116
117
/**
118
* Whether to match if any of the conditions match (OR) or all must match (AND)
119
* @return parameterized container annotation
120
*/
121
Class<?> parameterizedContainer() default Object.class;
122
}
123
124
/**
125
* Matches when specified beans are not present in the application context
126
* Most commonly used to provide default beans when user hasn't defined their own
127
*/
128
@Target({ElementType.TYPE, ElementType.METHOD})
129
@Retention(RetentionPolicy.RUNTIME)
130
@Documented
131
@Conditional(OnBeanCondition.class)
132
public @interface ConditionalOnMissingBean {
133
/**
134
* Bean classes that must not be present
135
* @return array of bean classes that should be absent
136
*/
137
Class<?>[] value() default {};
138
139
/**
140
* Bean type names that must not be present
141
* @return array of bean type names that should be absent
142
*/
143
String[] type() default {};
144
145
/**
146
* Bean names that must not be present
147
* @return array of bean names that should be absent
148
*/
149
String[] name() default {};
150
151
/**
152
* Classes to ignore when checking for missing beans
153
* @return array of classes to ignore
154
*/
155
Class<?>[] ignored() default {};
156
157
/**
158
* Bean types to ignore when checking for missing beans
159
* @return array of ignored bean types
160
*/
161
String[] ignoredType() default {};
162
163
/**
164
* Strategy for searching beans
165
* @return search strategy
166
*/
167
SearchStrategy search() default SearchStrategy.ALL;
168
169
/**
170
* Additional annotation that must be present on the beans
171
* @return annotation class
172
*/
173
Class<? extends Annotation> annotation() default Annotation.class;
174
175
/**
176
* Whether to match if any of the conditions match (OR) or all must match (AND)
177
* @return parameterized container annotation
178
*/
179
Class<?> parameterizedContainer() default Object.class;
180
}
181
182
/**
183
* Matches when there is exactly one primary bean of the specified type
184
* Used when multiple beans exist but only one is marked as primary
185
*/
186
@Target({ElementType.TYPE, ElementType.METHOD})
187
@Retention(RetentionPolicy.RUNTIME)
188
@Documented
189
@Conditional(OnBeanCondition.class)
190
public @interface ConditionalOnSingleCandidate {
191
/**
192
* Bean class for which there should be a single candidate
193
* @return the bean class
194
*/
195
Class<?> value() default Object.class;
196
197
/**
198
* Bean type for which there should be a single candidate
199
* @return the bean type name
200
*/
201
String type() default "";
202
203
/**
204
* Strategy for searching beans
205
* @return search strategy
206
*/
207
SearchStrategy search() default SearchStrategy.ALL;
208
}
209
```
210
211
**Usage Examples:**
212
213
```java
214
@Bean
215
@ConditionalOnMissingBean(DataSource.class)
216
public DataSource dataSource() {
217
// Creates default DataSource only if user hasn't defined one
218
return new HikariDataSource();
219
}
220
221
@Bean
222
@ConditionalOnBean(DataSource.class)
223
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
224
// Creates JdbcTemplate only when DataSource bean exists
225
return new JdbcTemplate(dataSource);
226
}
227
228
@AutoConfiguration
229
@ConditionalOnSingleCandidate(DataSource.class)
230
public class SingleDataSourceConfiguration {
231
// Applies when there's exactly one primary DataSource bean
232
}
233
```
234
235
### Property-Based Conditions
236
237
Conditional annotations that evaluate based on application properties and their values.
238
239
```java { .api }
240
/**
241
* Matches based on the presence and value of a single property
242
* Most flexible property-based condition
243
*/
244
@Target({ElementType.TYPE, ElementType.METHOD})
245
@Retention(RetentionPolicy.RUNTIME)
246
@Documented
247
@Conditional(OnPropertyCondition.class)
248
public @interface ConditionalOnProperty {
249
/**
250
* Property names to check (alternative to name)
251
* @return array of property names
252
*/
253
String[] value() default {};
254
255
/**
256
* Prefix to apply to property names
257
* @return property prefix
258
*/
259
String prefix() default "";
260
261
/**
262
* Property names to check
263
* @return array of property names
264
*/
265
String[] name() default {};
266
267
/**
268
* Expected value for the property
269
* @return expected property value
270
*/
271
String havingValue() default "";
272
273
/**
274
* Whether condition matches if property is missing
275
* @return true if condition should match when property is missing
276
*/
277
boolean matchIfMissing() default false;
278
279
/**
280
* Relaxed binding for property names
281
* @return true to enable relaxed binding
282
*/
283
boolean relaxedNames() default true;
284
}
285
286
/**
287
* Matches when all specified properties have expected values
288
* Used for multiple property conditions that must all be true
289
*/
290
@Target({ElementType.TYPE, ElementType.METHOD})
291
@Retention(RetentionPolicy.RUNTIME)
292
@Documented
293
@Conditional(OnPropertyCondition.class)
294
public @interface ConditionalOnProperties {
295
/**
296
* Properties that must all match their expected values
297
* @return array of ConditionalOnProperty annotations
298
*/
299
ConditionalOnProperty[] value();
300
}
301
302
/**
303
* Matches when boolean properties have expected values
304
* Simplified version for boolean property checks
305
*/
306
@Target({ElementType.TYPE, ElementType.METHOD})
307
@Retention(RetentionPolicy.RUNTIME)
308
@Documented
309
@Conditional(OnPropertyCondition.class)
310
public @interface ConditionalOnBooleanProperty {
311
/**
312
* Property name to check
313
* @return property name
314
*/
315
String name();
316
317
/**
318
* Prefix to apply to property name
319
* @return property prefix
320
*/
321
String prefix() default "";
322
323
/**
324
* Expected boolean value
325
* @return expected boolean value
326
*/
327
boolean value() default true;
328
329
/**
330
* Whether condition matches if property is missing
331
* @return true if condition should match when property is missing
332
*/
333
boolean matchIfMissing() default false;
334
}
335
```
336
337
**Usage Examples:**
338
339
```java
340
@AutoConfiguration
341
@ConditionalOnProperty(prefix = "app.features", name = "advanced", havingValue = "true")
342
public class AdvancedFeaturesAutoConfiguration {
343
// Only applies when app.features.advanced=true
344
}
345
346
@Bean
347
@ConditionalOnProperty(value = "spring.datasource.url", matchIfMissing = false)
348
public DataSource customDataSource(@Value("${spring.datasource.url}") String url) {
349
// Creates bean only when spring.datasource.url property is present
350
}
351
352
@AutoConfiguration
353
@ConditionalOnProperties({
354
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true"),
355
@ConditionalOnProperty(name = "feature.mode", havingValue = "advanced")
356
})
357
public class ConditionalFeatureConfiguration {
358
// Applies when both properties have expected values
359
}
360
```
361
362
### Environment and Platform Conditions
363
364
Conditional annotations that evaluate based on environment characteristics, deployment context, and platform detection.
365
366
```java { .api }
367
/**
368
* Matches when application is running on a specific cloud platform
369
* Automatically detects cloud platforms based on environment variables and system properties
370
*/
371
@Target({ElementType.TYPE, ElementType.METHOD})
372
@Retention(RetentionPolicy.RUNTIME)
373
@Documented
374
@Conditional(OnCloudPlatformCondition.class)
375
public @interface ConditionalOnCloudPlatform {
376
/**
377
* Cloud platform that must be detected
378
* @return required cloud platform
379
*/
380
CloudPlatform value();
381
}
382
383
/**
384
* Matches when application is running on a specific Java version or range
385
* Useful for enabling features that require specific Java versions
386
*/
387
@Target({ElementType.TYPE, ElementType.METHOD})
388
@Retention(RetentionPolicy.RUNTIME)
389
@Documented
390
@Conditional(OnJavaCondition.class)
391
public @interface ConditionalOnJava {
392
/**
393
* Java version range specification
394
* @return Java version range
395
*/
396
Range range() default Range.EQUAL_OR_NEWER;
397
398
/**
399
* Specific Java version to match against
400
* @return Java version
401
*/
402
JavaVersion value();
403
404
enum Range {
405
EQUAL_OR_NEWER, OLDER_THAN
406
}
407
}
408
409
/**
410
* Matches when application is deployed as a WAR file
411
* Used to enable WAR-specific configurations
412
*/
413
@Target({ElementType.TYPE, ElementType.METHOD})
414
@Retention(RetentionPolicy.RUNTIME)
415
@Documented
416
@Conditional(OnWarDeploymentCondition.class)
417
public @interface ConditionalOnWarDeployment {
418
}
419
420
/**
421
* Matches when application is NOT deployed as a WAR file
422
* Used for embedded server configurations
423
*/
424
@Target({ElementType.TYPE, ElementType.METHOD})
425
@Retention(RetentionPolicy.RUNTIME)
426
@Documented
427
@Conditional(OnWarDeploymentCondition.class)
428
public @interface ConditionalOnNotWarDeployment {
429
}
430
431
/**
432
* Matches based on web application type (servlet, reactive, or none)
433
* Essential for web-specific auto-configurations
434
*/
435
@Target({ElementType.TYPE, ElementType.METHOD})
436
@Retention(RetentionPolicy.RUNTIME)
437
@Documented
438
@Conditional(OnWebApplicationCondition.class)
439
public @interface ConditionalOnWebApplication {
440
/**
441
* Type of web application required
442
* @return web application type
443
*/
444
Type type() default Type.ANY;
445
446
enum Type {
447
ANY, SERVLET, REACTIVE
448
}
449
}
450
451
/**
452
* Matches when application is not a web application
453
* Used for non-web configurations
454
*/
455
@Target({ElementType.TYPE, ElementType.METHOD})
456
@Retention(RetentionPolicy.RUNTIME)
457
@Documented
458
@Conditional(OnNotWebApplicationCondition.class)
459
public @interface ConditionalOnNotWebApplication {
460
}
461
```
462
463
**Usage Examples:**
464
465
```java
466
@AutoConfiguration
467
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
468
public class KubernetesSpecificConfiguration {
469
// Only applies when running on Kubernetes
470
}
471
472
@Bean
473
@ConditionalOnJava(value = JavaVersion.SEVENTEEN, range = Range.EQUAL_OR_NEWER)
474
public ModernJavaService modernJavaService() {
475
// Only creates bean on Java 17 or newer
476
}
477
478
@AutoConfiguration
479
@ConditionalOnWebApplication(type = Type.SERVLET)
480
@ConditionalOnNotWarDeployment
481
public class EmbeddedServletConfiguration {
482
// Applies to servlet web apps not deployed as WAR
483
}
484
```
485
486
### Resource and Expression Conditions
487
488
Advanced conditional annotations for specific resource requirements and custom logic.
489
490
```java { .api }
491
/**
492
* Matches when specified resources are available on the classpath
493
* Useful for configuration files or templates
494
*/
495
@Target({ElementType.TYPE, ElementType.METHOD})
496
@Retention(RetentionPolicy.RUNTIME)
497
@Documented
498
@Conditional(OnResourceCondition.class)
499
public @interface ConditionalOnResource {
500
/**
501
* Resources that must be present on the classpath
502
* @return array of resource paths
503
*/
504
String[] resources() default {};
505
}
506
507
/**
508
* Matches based on SpEL (Spring Expression Language) evaluation
509
* Provides maximum flexibility for complex conditions
510
*/
511
@Target({ElementType.TYPE, ElementType.METHOD})
512
@Retention(RetentionPolicy.RUNTIME)
513
@Documented
514
@Conditional(OnExpressionCondition.class)
515
public @interface ConditionalOnExpression {
516
/**
517
* SpEL expression that must evaluate to true
518
* @return Spring expression
519
*/
520
String value();
521
}
522
523
/**
524
* Matches when JNDI is available and optionally when specific JNDI locations exist
525
* Used for enterprise application server configurations
526
*/
527
@Target({ElementType.TYPE, ElementType.METHOD})
528
@Retention(RetentionPolicy.RUNTIME)
529
@Documented
530
@Conditional(OnJndiCondition.class)
531
public @interface ConditionalOnJndi {
532
/**
533
* JNDI locations that must be available
534
* @return array of JNDI locations
535
*/
536
String[] value() default {};
537
}
538
539
/**
540
* Matches based on threading model (virtual threads support)
541
* Used for Java 21+ virtual threads features
542
*/
543
@Target({ElementType.TYPE, ElementType.METHOD})
544
@Retention(RetentionPolicy.RUNTIME)
545
@Documented
546
@Conditional(OnThreadingCondition.class)
547
public @interface ConditionalOnThreading {
548
/**
549
* Threading model required
550
* @return threading model
551
*/
552
Threading value();
553
554
enum Threading {
555
PLATFORM, VIRTUAL
556
}
557
}
558
```
559
560
**Usage Examples:**
561
562
```java
563
@Bean
564
@ConditionalOnResource(resources = "classpath:templates/custom-error.html")
565
public CustomErrorViewResolver customErrorViewResolver() {
566
// Only creates bean if custom error template exists
567
}
568
569
@AutoConfiguration
570
@ConditionalOnExpression("${app.features.experimental:false} && ${app.env} == 'development'")
571
public class ExperimentalFeaturesConfiguration {
572
// Complex condition using SpEL
573
}
574
575
@Bean
576
@ConditionalOnJndi("java:comp/env/jdbc/MyDataSource")
577
public DataSource jndiDataSource() {
578
// Creates bean only if JNDI DataSource is available
579
}
580
```
581
582
## Types
583
584
### Condition Support Types
585
586
```java { .api }
587
/**
588
* Search strategy for bean conditions
589
*/
590
public enum SearchStrategy {
591
/**
592
* Search only the current application context
593
*/
594
CURRENT,
595
596
/**
597
* Search the current application context and all ancestors
598
*/
599
ANCESTORS,
600
601
/**
602
* Search the current application context and all ancestors and descendants
603
*/
604
ALL
605
}
606
607
/**
608
* Supported cloud platforms for automatic detection
609
*/
610
public enum CloudPlatform {
611
NONE(""),
612
CLOUD_FOUNDRY("Cloud Foundry"),
613
HEROKU("Heroku"),
614
SAP("SAP Cloud Platform"),
615
KUBERNETES("Kubernetes"),
616
AZURE("Microsoft Azure"),
617
AWS("Amazon Web Services"),
618
GOOGLE_CLOUD("Google Cloud Platform");
619
620
private final String name;
621
622
public String getName();
623
public boolean isActive(Environment environment);
624
}
625
626
/**
627
* Java version enumeration for version-based conditions
628
*/
629
public enum JavaVersion {
630
EIGHT(8, "1.8", "java.util.Optional"),
631
NINE(9, "9", "java.lang.Runtime$Version"),
632
TEN(10, "10", "java.util.List.copyOf"),
633
ELEVEN(11, "11", "java.lang.String.strip"),
634
TWELVE(12, "12", "java.lang.String.indent"),
635
THIRTEEN(13, "13", "java.lang.String.formatted"),
636
FOURTEEN(14, "14", "java.lang.Record"),
637
FIFTEEN(15, "15", "java.lang.CharSequence.isEmpty"),
638
SIXTEEN(16, "16", "java.lang.Record.getRecordComponents"),
639
SEVENTEEN(17, "17", "java.util.random.RandomGenerator"),
640
EIGHTEEN(18, "18", "java.lang.String.stripIndent"),
641
NINETEEN(19, "19", "java.util.concurrent.StructuredTaskScope"),
642
TWENTY(20, "20", "java.lang.foreign.Arena"),
643
TWENTY_ONE(21, "21", "java.lang.Thread.ofVirtual");
644
645
public boolean isEqualOrNewerThan(JavaVersion version);
646
public boolean isOlderThan(JavaVersion version);
647
}
648
```
649
650
### Condition Evaluation Types
651
652
```java { .api }
653
/**
654
* Result of a condition evaluation
655
*/
656
public class ConditionOutcome {
657
658
/**
659
* Create a matching outcome with a message
660
* @param match whether the condition matches
661
* @param message descriptive message
662
*/
663
public ConditionOutcome(boolean match, String message);
664
665
/**
666
* Create a matching outcome with a ConditionMessage
667
* @param match whether the condition matches
668
* @param message condition message
669
*/
670
public ConditionOutcome(boolean match, ConditionMessage message);
671
672
/**
673
* Whether the condition matches
674
* @return true if condition matches
675
*/
676
public boolean isMatch();
677
678
/**
679
* Get the outcome message
680
* @return condition message
681
*/
682
public String getMessage();
683
684
/**
685
* Create a matching outcome with no message
686
* @return matching ConditionOutcome
687
*/
688
public static ConditionOutcome match();
689
690
/**
691
* Create a non-matching outcome with no message
692
* @return non-matching ConditionOutcome
693
*/
694
public static ConditionOutcome noMatch();
695
}
696
697
/**
698
* Builder for condition messages
699
*/
700
public final class ConditionMessage {
701
702
/**
703
* Create an empty condition message
704
* @return empty ConditionMessage
705
*/
706
public static ConditionMessage empty();
707
708
/**
709
* Create a condition message with formatted text
710
* @param message message template
711
* @param args message arguments
712
* @return ConditionMessage instance
713
*/
714
public static ConditionMessage of(String message, Object... args);
715
716
/**
717
* Add additional condition information
718
* @param condition condition name
719
* @param args condition arguments
720
* @return ConditionMessage with additional condition
721
*/
722
public ConditionMessage andCondition(String condition, Object... args);
723
724
/**
725
* Add reason for the condition result
726
* @param reason reason message
727
* @param args reason arguments
728
* @return ConditionMessage with reason
729
*/
730
public ConditionMessage because(String reason, Object... args);
731
}
732
```