404 Not Found

404 Not Found


nginx

Configuration Management

Configuration management serves as the bridge between development and production—one codebase, multiple configurations, and switching between environments requires just a single line of parameters.

1. What You'll Learn


2. A True Story of an Operations Engineer

(1) Pain Point: Configurations are scattered all over the place

Bob is an operations engineer at OrderFlow, and every deployment feels like an "archaeological dig": database passwords are hard-coded into the code, and the configurations for the test and production environments are mixed together in a single file. Someone changed the production database password but forgot to update the code, causing the system to go down for two hours. When Charlie pressed him about the SLA, Bob could only explain, with a sigh, that "configuration management is a mess."

(2) Solutions for Spring Boot Profiles

Spring Boot uses the Profile mechanism to separate configurations for multiple environments:

YAML
# application-dev.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/orderflow_dev
    username: dev_user
    password: dev_pass
YAML
# application-prod.yml
spring:
  datasource:
    url: jdbc:mysql://prod-db.internal:3306/orderflow
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}

(3) Revenue

After Bob refactored the code using Profile and environment variables, the development environment now uses dev and the production environment uses prod. Sensitive information no longer appears in the code repository, and switching deployments requires only --spring.profiles.active=prod, reducing downtime caused by configuration errors to zero.


3. Profile: Multi-Environment Configuration

(1) Profile File Naming Conventions

Spring Boot loads profile configurations according to the application-{profile}.yml naming convention:

TEXT
src/main/resources/
├── application.yml            # Common config (shared)
├── application-dev.yml        # Dev profile
├── application-prod.yml       # Prod profile
└── application-test.yml       # Test profile
100%
graph TD
    A["application.yml<br/>Common Config"] --> B["application-dev.yml<br/>Dev Overrides"]
    A --> C["application-prod.yml<br/>Prod Overrides"]
    A --> D["application-test.yml<br/>Test Overrides"]
    B --> E["Merged Config<br/>Profile=dev"]
    C --> F["Merged Config<br/>Profile=prod"]
Activation Method Command Priority
Configuration File spring.profiles.active=dev in application.yml Minimum
Environment Variable SPRING_PROFILES_ACTIVE=dev Chinese
Command-line argument --spring.profiles.active=dev Maximum

(1) ▶ Example: Profile

YAML
# application.yml (shared)
spring:
  application:
    name: orderflow-service
  profiles:
    active: dev

server:
  port: 8080

Output:

TEXT
Configuration applied successfully
YAML
# application-dev.yml
spring:
  datasource:
    url: jdbc:h2:mem:orderflow_dev
    username: sa
    password:
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true

logging:
  level:
    com.orderflow: DEBUG
YAML
# application-prod.yml
spring:
  datasource:
    url: jdbc:mysql://${DB_HOST:localhost}:3306/orderflow
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  jpa:
    hibernate:
      ddl-auto: validate
    show-sql: false

logging:
  level:
    com.orderflow: WARN

4. Comparison of @Value and @ConfigurationProperties

(1) Two Injection Methods

(1) ▶ Example: @Value Injection

JAVA
@RestController
public class OrderController {

    @Value("${orderflow.max-items-per-order:100}")
    private int maxItemsPerOrder;

    @Value("${orderflow.default-currency:USD}")
    private String defaultCurrency;

    @GetMapping("/api/config/check")
    public Map<String, Object> checkConfig() {
        return Map.of(
            "maxItemsPerOrder", maxItemsPerOrder,
            "defaultCurrency", defaultCurrency
        );
    }
}

Output:

TEXT
// Execution Successful

(2) ▶ Example: Type-safe binding with @ConfigurationProperties

JAVA
@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
    int maxItemsPerOrder,
    String defaultCurrency,
    Duration orderTimeout,
    ShippingConfig shipping
) {
    public record ShippingConfig(
        boolean freeShippingEnabled,
        BigDecimal freeShippingThreshold
    ) {}
}

// Enable in main class or config class
@EnableConfigurationProperties(OrderFlowProperties.class)

Output:

TEXT
// Execution Successful
Dimension @Value @ConfigurationProperties
Type Safety Weak (primarily String) Strong (automatic type conversion)
Nested objects Not supported Supported
Collection Binding Not Supported Supports List/Map
Verification None In conjunction with @Validated
IDE Support No hints Auto-completion (metadata)
Use Cases Small Number of Simple Values Structured Business Configuration

(3) ▶ Example: YAML and ConfigurationProperties Mappings

YAML
orderflow:
  max-items-per-order: 50
  default-currency: USD
  order-timeout: 30m
  shipping:
    free-shipping-enabled: true
    free-shipping-threshold: 49.99

Output:

TEXT
The configuration has taken effect.
JAVA
// Access example
@Component
public class OrderService {
    private final OrderFlowProperties props;

    public OrderService(OrderFlowProperties props) {
        this.props = props;
    }

    public boolean isFreeShipping(BigDecimal orderTotal) {
        return props.shipping().freeShippingEnabled()
            && orderTotal.compareTo(props.shipping().freeShippingThreshold()) >= 0;
    }
}

5. Configuration Priority Hierarchy

(1) Priority from highest to lowest

100%
graph TD
    A["1. Command Line Args<br/>--server.port=9090"] --> B["2. JNDI Attributes"]
    B --> C["3. Java System Properties<br/>-Dserver.port=9090"]
    C --> D["4. OS Environment Variables<br/>SERVER_PORT=9090"]
    D --> E["5. application-{profile}.yml<br/>Profile-specific"]
    E --> F["6. application.yml<br/>Default config"]
    F --> G["7. @Default Values<br/>In code annotations"]
Priority Source Example
1 (Highest) Command-line arguments --server.port=9090
2 JNDI Properties java:comp/env/...
3 JVM System Properties -Dserver.port=9090
4 OS Environment Variables SERVER_PORT=9090
5 Profile application-prod.yml
6 Default Configuration File application.yml
7 (minimum) Default value @Value("${x:default}")
💡 Tip: In a production environment, it is recommended to override sensitive configurations using environment variables or command-line arguments; do not include passwords in configuration files.


6. Nested Configuration and Collection Binding

(1) Binding Lists and Maps

(1) ▶ Example: List and Map Configuration

YAML
orderflow:
  supported-currencies:
    - USD
    - EUR
    - GBP
  payment-gateways:
    stripe:
      api-key: ${STRIPE_API_KEY}
      webhook-secret: ${STRIPE_WEBHOOK_SECRET}
    paypal:
      client-id: ${PAYPAL_CLIENT_ID}
      secret: ${PAYPAL_SECRET}

Output:

TEXT
CI/CD pipeline configuration has been loaded
Pipeline status: passed
Tests: 12 passed, 0 failed
JAVA
@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
    List<String> supportedCurrencies,
    Map<String, GatewayConfig> paymentGateways
) {
    public record GatewayConfig(
        String apiKey,
        String webhookSecret,
        String clientId,
        String secret
    ) {}
}

7. Comprehensive Example: The Complete OrderFlow Configuration System

JAVA
// OrderFlowProperties.java
package com.orderflow.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.List;
import java.util.Map;

@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
    int maxItemsPerOrder,
    String defaultCurrency,
    Duration orderTimeout,
    ShippingConfig shipping,
    List<String> supportedCurrencies,
    Map<String, GatewayConfig> paymentGateways
) {
    public record ShippingConfig(
        boolean freeShippingEnabled,
        BigDecimal freeShippingThreshold
    ) {}

    public record GatewayConfig(
        String apiKey,
        String webhookSecret,
        String clientId,
        String secret
    ) {}
}

// AppConfig.java
package com.orderflow.config;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(OrderFlowProperties.class)
public class AppConfig {}
YAML
# application.yml
spring:
  application:
    name: orderflow-service
  profiles:
    active: dev

orderflow:
  max-items-per-order: 50
  default-currency: USD
  order-timeout: 30m
  supported-currencies:
    - USD
    - EUR
    - GBP
  shipping:
    free-shipping-enabled: true
    free-shipping-threshold: 49.99
  payment-gateways:
    stripe:
      api-key: ${STRIPE_API_KEY:dev-key}
      webhook-secret: ${STRIPE_WEBHOOK_SECRET:dev-secret}

❓ FAQ

Q Which should I choose, @ConfigurationProperties or @Value?
A Use @ConfigurationProperties for structured configuration (type safety, nesting, IDE support), and @Value for a small number of simple values. Avoid mixing too many of them in a single project.
Q How can I prevent sensitive information from being leaked to the code repository?
A 1) Use the ${ENV_VAR} placeholder in configuration files to reference environment variables; 2) Exclude sensitive configuration files in .gitignore; 3) Use K8s Secrets or Vault to manage secrets in production environments.
Q How are Profile configurations and default configurations merged?
A Spring Boot first loads the default configuration, then uses the Profile configuration to override properties that match. For different properties, they complement each other; for matching properties, the Profile takes precedence.
Q How do you write a list in YAML within the "Properties" section?
A orderflow.supported-currencies[0]=USD, orderflow.supported-currencies[1]=EUR. List indices start at 0.
Q How do I dynamically switch profiles in code?
A Dynamically switching profiles in code is not recommended. Profiles should be determined at startup. If you need to dynamically switch configurations at runtime, use Spring Cloud Config or a custom configuration refresh mechanism.
Q What are the limitations of using record as a ConfigurationProperties?
A record is immutable and is suitable for read-only configurations. Spring Boot 3.x supports record binding. However, it cannot be used with @Validated for JSR-380 validation (since record lacks a no-argument constructor), so a class must be used instead.

📖 Summary


📝 Exercises

  1. Basic Exercise (Difficulty ⭐): Configure two profiles for OrderFlow—one for dev and one for prod. The dev profile uses the H2 in-memory database, while the prod profile uses MySQL. Switch between them using command-line arguments.

  2. Advanced Problem (Difficulty ⭐⭐): Use @ConfigurationProperties to create PaymentGatewayProperties, which includes API key configurations for Stripe and PayPal; inject the key values via environment variables.

  3. Challenge (Difficulty: ⭐⭐⭐): Implement a custom PropertySource to load configuration from a remote configuration center (you may use a mocked HTTP endpoint), and consider the design intent behind the Spring Boot Environment abstraction.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏