Spring Boot
Configuration Properties
Immutable Objects
Java
Application Development

Immutable ConfigurationProperties

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Spring Boot, immutable @ConfigurationProperties classes let you bind configuration into objects that cannot be changed after creation. That makes configuration safer to reason about, easier to test, and less error-prone than mutable beans filled through setters.

Why Immutability Helps

Configuration is usually read, not modified. So immutable objects are a natural fit.

Benefits include:

  • no accidental mutation after startup
  • easier thread-safe sharing
  • required values can be enforced at construction time
  • configuration classes become simple value objects

Instead of creating a bean and then populating it through setters, Spring Boot can construct the object directly from configuration.

Constructor-Bound Properties

A typical immutable configuration properties class uses final fields and constructor binding semantics. In modern Spring Boot, a Java record is often the cleanest option.

java
1import org.springframework.boot.context.properties.ConfigurationProperties;
2
3@ConfigurationProperties(prefix = "app.storage")
4public record StorageProperties(String bucket, int timeoutSeconds) {
5}

In application.yml:

yaml
1app:
2  storage:
3    bucket: uploads
4    timeout-seconds: 30

Spring binds the external values to the record components when creating the bean.

Enable Scanning or Registration

Spring must know to create the properties bean.

You can use configuration properties scanning:

java
1import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
2import org.springframework.boot.autoconfigure.SpringBootApplication;
3
4@SpringBootApplication
5@ConfigurationPropertiesScan
6public class Application {
7}

Or register the class explicitly with @EnableConfigurationProperties.

Using a Class Instead of a Record

If records are not an option, a final class with constructor parameters works too.

java
1import org.springframework.boot.context.properties.ConfigurationProperties;
2
3@ConfigurationProperties(prefix = "app.mail")
4public class MailProperties {
5    private final String host;
6    private final int port;
7
8    public MailProperties(String host, int port) {
9        this.host = host;
10        this.port = port;
11    }
12
13    public String getHost() {
14        return host;
15    }
16
17    public int getPort() {
18        return port;
19    }
20}

The important idea is the same: no setters, no mutable state.

Validation Still Works

Immutability does not prevent validation. You can still annotate fields or constructor-bound values with validation constraints.

java
1import jakarta.validation.constraints.Min;
2import jakarta.validation.constraints.NotBlank;
3import org.springframework.boot.context.properties.ConfigurationProperties;
4import org.springframework.validation.annotation.Validated;
5
6@Validated
7@ConfigurationProperties(prefix = "app.api")
8public record ApiProperties(
9    @NotBlank String baseUrl,
10    @Min(1) int retries
11) {
12}

If configuration is invalid, the application fails fast during startup.

Injection and Usage

Once registered, inject the properties bean like any other dependency.

java
1import org.springframework.stereotype.Service;
2
3@Service
4public class StorageService {
5    private final StorageProperties properties;
6
7    public StorageService(StorageProperties properties) {
8        this.properties = properties;
9    }
10}

The service gets a stable configuration object that cannot be mutated by mistake later.

Defaults and Nested Properties

Immutability also works with nested configuration objects, but you should think explicitly about defaults. If a value is optional, give it a sensible default in the constructor or record declaration strategy you use, rather than relying on later mutation.

That keeps the object valid the moment it is created, which is one of the main benefits of immutable configuration binding in the first place.

Common Pitfalls

A common mistake is mixing immutable intent with setter methods. If setters exist and are used for binding, the class is no longer truly immutable.

Another mistake is forgetting to enable configuration-properties scanning or explicit registration, which leaves the class unbound and unavailable for injection.

Developers also sometimes assume immutability removes the need for validation. It does not. Immutable bad configuration is still bad configuration.

Summary

  • Immutable @ConfigurationProperties are a strong fit for application settings.
  • Records are often the cleanest modern Spring Boot option.
  • Constructor-based binding avoids mutable setters.
  • Validation annotations still work and are important.
  • Enable scanning or explicit registration so Spring actually creates the properties bean.

Course illustration
Course illustration

All Rights Reserved.