javabeginner

Environment Configuration Management

Load configuration from environment variables, properties files, and system properties with defaults.

java
import java.io.*;
import java.nio.file.*;
import java.util.*;

public class AppConfig {
    private final Properties props = new Properties();

    private AppConfig() {
        // Load in order (later values override earlier)
        loadFromClasspath("application.properties");
        loadFromFile("config/application.properties");
        loadFromEnv();
        loadFromSystemProps();
    }

    // Singleton
    private static final AppConfig INSTANCE = new AppConfig();
    public static AppConfig get() { return INSTANCE; }

    // Typed getters with defaults
    public String getString(String key, String defaultVal) {
        return props.getProperty(key, defaultVal);
    }

    public int getInt(String key, int defaultVal) {
        String val = props.getProperty(key);
        if (val == null) return defaultVal;
        return Integer.parseInt(val.trim());
    }

    public boolean getBool(String key, boolean defaultVal) {
        String val = props.getProperty(key);
        if (val == null) return defaultVal;
        return Boolean.parseBoolean(val.trim());
    }

    public List<String> getList(String key) {
        String val = props.getProperty(key, "");
        return val.isBlank() ? List.of()
            : Arrays.stream(val.split(",")).map(String::trim).toList();
    }

    // Required — throws if missing
    public String require(String key) {
        String val = props.getProperty(key);
        if (val == null || val.isBlank()) {
            throw new IllegalStateException("Missing required config: " + key);
        }
        return val;
    }

    // --- Loaders ---
    private void loadFromClasspath(String filename) {
        try (var is = getClass().getClassLoader().getResourceAsStream(filename)) {
            if (is != null) props.load(is);
        } catch (IOException e) {
            System.err.println("Warning: couldn't load " + filename);
        }
    }

    private void loadFromFile(String path) {
        Path file = Path.of(path);
        if (Files.exists(file)) {
            try (var reader = Files.newBufferedReader(file)) {
                props.load(reader);
            } catch (IOException e) {
                System.err.println("Warning: couldn't load " + path);
            }
        }
    }

    private void loadFromEnv() {
        // Map env vars: APP_DB_URL → app.db.url
        System.getenv().forEach((key, value) -> {
            String propKey = key.toLowerCase().replace('_', '.');
            props.setProperty(propKey, value);
        });
    }

    private void loadFromSystemProps() {
        props.putAll(System.getProperties());
    }

    public static void main(String[] args) {
        AppConfig config = AppConfig.get();
        String dbUrl = config.getString("app.db.url", "jdbc:h2:mem:test");
        int port = config.getInt("app.port", 8080);
        boolean debug = config.getBool("app.debug", false);

        System.out.printf("DB: %s, Port: %d, Debug: %b%n", dbUrl, port, debug);
    }
}

Use Cases

  • Application configuration management
  • Environment-specific settings
  • 12-factor app configuration pattern

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.