java 49 lines · 5 steps

Feature-flagged beans with Spring @ConditionalOnProperty

Swap an invoice delivery strategy at startup based on a config property, with a safe default.

Explained by highlit
1package com.acme.billing.config;
2 
3import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
4import org.springframework.boot.context.properties.ConfigurationProperties;
5import org.springframework.boot.context.properties.EnableConfigurationProperties;
6import org.springframework.context.annotation.Bean;
7import org.springframework.context.annotation.Configuration;
8 
9@Configuration
10@EnableConfigurationProperties(InvoiceFeatureProperties.class)
11public class InvoiceFeatureConfig {
12 
13 @Bean
14 @ConditionalOnProperty(prefix = "features.invoicing", name = "async-delivery", havingValue = "true")
15 public InvoiceDeliveryStrategy asyncInvoiceDeliveryStrategy(InvoiceMailer mailer,
16 InvoiceFeatureProperties properties) {
17 return new AsyncInvoiceDeliveryStrategy(mailer, properties.getBatchSize());
18 }
19 
20 @Bean
21 @ConditionalOnProperty(prefix = "features.invoicing", name = "async-delivery",
22 havingValue = "false", matchIfMissing = true)
23 public InvoiceDeliveryStrategy syncInvoiceDeliveryStrategy(InvoiceMailer mailer) {
24 return new SyncInvoiceDeliveryStrategy(mailer);
25 }
26}
27 
28@ConfigurationProperties(prefix = "features.invoicing")
29class InvoiceFeatureProperties {
30 
31 private boolean asyncDelivery = false;
32 private int batchSize = 50;
33 
34 public boolean isAsyncDelivery() {
35 return asyncDelivery;
36 }
37 
38 public void setAsyncDelivery(boolean asyncDelivery) {
39 this.asyncDelivery = asyncDelivery;
40 }
41 
42 public int getBatchSize() {
43 return batchSize;
44 }
45 
46 public void setBatchSize(int batchSize) {
47 this.batchSize = batchSize;
48 }
49}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1@ConditionalOnProperty lets one property select which implementation of an interface gets wired.
  2. 2Pairing havingValue "true" against "false" with matchIfMissing guarantees exactly one bean always exists.
  3. 3Binding external config to a typed properties class keeps tunables like batch size out of your code.

Related explainers

typescript
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import localeFrExtra from '@angular/common/locales/extra/fr';
import localeDe from '@angular/common/locales/de';

Locale-aware bootstrapping in Angular

i18n localization dependency-injection
Intermediate 8 steps
typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
 

Validating env config at boot in NestJS

configuration schema-validation environment-variables
Intermediate 8 steps
java
@Component
@Converter
public class EncryptedStringConverter implements AttributeConverter<String, String> {
 

Transparent column encryption in Spring & JPA

encryption aes-gcm jpa-converter
Advanced 10 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { InjectRepository } from '@nestjs/typeorm';

A cache-aside country lookup in NestJS

cache-aside dependency-injection batch-lookup
Intermediate 8 steps
typescript
import { Injectable, effect, signal, computed } from '@angular/core';
 
interface Preferences {
  theme: 'light' | 'dark';

A signal-based preferences store in Angular

signals state-management persistence
Intermediate 7 steps
java
public static Map<String, String> parseCookieHeader(String header) {
    Map<String, String> cookies = new LinkedHashMap<>();
    if (header == null || header.isBlank()) {
        return cookies;

Parsing an HTTP Cookie header in Java

string-parsing http url-decoding
Intermediate 6 steps

Share this explainer

Here's the card — post it anywhere.

Feature-flagged beans with Spring @ConditionalOnProperty — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code