Spring Boot @ConfigurationProperties
– The Cleanest Way to Manage Configuration
Introduction
In a microservices architecture or a large-scale Spring Boot application, managing configurations efficiently is crucial. Hardcoded values in Java classes or excessive use of @Value
annotations often lead to scattered, unmaintainable, and error-prone code. This is where @ConfigurationProperties
comes in!
Spring Boot provides @ConfigurationProperties
as a powerful way to bind external configurations to strongly-typed Java objects, promoting clean code, type safety, and easy management.
In this article, we’ll explore: ✔️ Why @ConfigurationProperties
is better than @Value
✔️ How it promotes clean code and maintainability
✔️ A basic implementation with a real-world example
✔️ Common best practices
🚀 Why Not Use @Value
Everywhere?
While @Value
is handy for injecting properties into Spring components, it has several drawbacks:
🔴 Scattered Configurations: Each property requires a separate @Value
, making it hard to track multiple configurations.
🔴 No Type Safety: @Value
only injects String values, requiring manual conversion for numbers, lists, or complex structures.
🔴 Difficult to Test & Maintain: Over time, excessive @Value
usage makes testing and refactoring difficult.
Here’s an example of bad practice using @Value
:
@Component
public class PaymentService {
@Value("${payment.api.url}")
private String apiUrl;
@Value("${payment.timeout}")
private int timeout;
public void processPayment() {
System.out.println("API URL: " + apiUrl);
System.out.println("Timeout: " + timeout);
}
}
Problems with this approach?
- Configuration values are scattered across multiple classes.
- Harder to manage and update properties.
- Lacks type safety and structured configuration.
✅ Using @ConfigurationProperties
for Clean, Maintainable Code
@ConfigurationProperties
solves these issues by grouping related configurations into a structured Java class.
🔹 Step 1: Define the Properties in application.properties
payment.api.url=https://api.payment.com
payment.timeout=5000
payment.retry.count=3
🔹 Step 2: Create a Configuration Class
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "payment")
public class PaymentProperties {
private String apiUrl;
private int timeout;
private int retryCount;
// Getters and Setters
public String getApiUrl() {
return apiUrl;
}
public void setApiUrl(String apiUrl) {
this.apiUrl = apiUrl;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public int getRetryCount() {
return retryCount;
}
public void setRetryCount(int retryCount) {
this.retryCount = retryCount;
}
}
🔹 Step 3: Inject and Use It in a Service
import org.springframework.stereotype.Service;
@Service
public class PaymentService {
private final PaymentProperties paymentProperties;
public PaymentService(PaymentProperties paymentProperties) {
this.paymentProperties = paymentProperties;
}
public void processPayment() {
System.out.println("API URL: " + paymentProperties.getApiUrl());
System.out.println("Timeout: " + paymentProperties.getTimeout());
System.out.println("Retry Count: " + paymentProperties.getRetryCount());
}
}
🚀 Benefits of Using @ConfigurationProperties
To ensure Spring Boot processes @ConfigurationProperties
, add this dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
🔚 Conclusion
Spring Boot’s @ConfigurationProperties
is a must-use feature for clean, maintainable, and scalable applications. It improves type safety, supports structured configurations, enables validation, and enhances testability.
Say goodbye to scattered @Value
annotations and embrace @ConfigurationProperties
for a cleaner, more robust codebase! 🚀