Configuration & Profiles
Bu modülde MiniBank uygulamasının ortamdan ortama değişen ayarlarını kodu değiştirmeden yönetmeyi öğreneceğiz. Amaç sadece application.yml okumak değil; dev, test ve prod ortamlarında güvenli, izlenebilir ve tip güvenli configuration modeli kurmak.
Kodu değiştirmeden uygulamanın davranışını güvenli şekilde yönetebileceksin.
Config mantığını oturtacaksın
Hangi bilgi kodda kalmalı, hangi bilgi configuration’a taşınmalı ayrımını netleştireceksin.
Profile bazlı davranış kuracaksın
Dev, test ve prod için farklı ayarları aynı uygulama koduyla yönetmeyi göreceksin.
Typed config yazacaksın
@ConfigurationProperties ile string tabanlı dağınık config yerine okunabilir Java objeleri kullanacaksın.
Önce ortak dili netleştirelim.
Configuration konusu basit görünür ama production’da en çok hata çıkaran alanlardan biridir. Bunun sebebi çoğu zaman ayarların neyi ifade ettiğinin, nereden geldiğinin ve hangi ortamda override edildiğinin net olmamasıdır.
Configuration
Basitçe: Uygulamanın çalışma ayarlarıdır. Spring Boot’ta: port, database URL, feature flag, timeout, limit ve external servis adresleri configuration ile yönetilir.
Property
Basitçe: Anahtar-değer şeklinde tutulan tek bir ayardır. Spring Boot’ta: server.port=8081 veya minibank.transfer.daily-limit=50000 gibi değerlerdir.
application.yml
Basitçe: Uygulamanın ana ayar dosyasıdır. Spring Boot’ta: hiyerarşik yapı ile okunabilir config yazmamızı sağlar.
Profile
Basitçe: Uygulamanın hangi ortam modunda çalışacağını belirtir. Spring Boot’ta: dev, test, prod gibi ortam davranışları ayrılır.
@ConfigurationProperties
Basitçe: Config değerlerini Java class’ına bağlar. Spring Boot’ta: dağınık @Value kullanımı yerine tip güvenli ve merkezi config modeli sağlar.
@Profile
Basitçe: Bir bean’in sadece belirli profilde oluşmasını sağlar. Spring Boot’ta: dev ortamında fake servis, prod ortamında gerçek servis kullanmak için tercih edilir.
Environment Variable
Basitçe: Uygulama dışından verilen ortam değişkenidir. Spring Boot’ta: container, Kubernetes veya CI/CD üzerinden değer override etmek için kullanılır.
Secret
Basitçe: Gizli tutulması gereken ayardır. Spring Boot’ta: password, token, API key gibi bilgiler repo’ya yazılmamalı; dış kaynaklardan verilmelidir.
Configuration, uygulamanın davranışını koddan ayırma disiplinidir.
Bir Spring Boot uygulaması sadece Java class’larından oluşmaz. Hangi portta çalışacağı, hangi database’e bağlanacağı, hangi external servisi çağıracağı, log seviyesinin ne olacağı ve hangi özelliğin açık kalacağı da uygulamanın davranışını belirler. Bunların tamamını kodun içine gömersek, her ortam değişiminde yeniden build almak zorunda kalırız.
7.1 Configuration neden var?
En basit haliyle configuration, kodu değiştirmeden davranış değiştirme ihtiyacından doğar. Development ortamında H2 ya da local PostgreSQL kullanmak isteyebiliriz. Production’da ise gerçek database, gerçek external servis adresleri, daha sıkı timeout değerleri ve daha kontrollü log seviyeleri kullanırız.
Bu ayrım yapılmazsa kodun içine şu tip bilgiler yayılır: database URL, servis adresleri, limitler, flag’ler, token değerleri, timeout süreleri. Başta pratik gibi görünür ama birkaç ortam ve birkaç mikroservis sonra yönetilemez hale gelir.
Kötü yaklaşım
Her servis içinde sabit URL, sabit limit veya ortam kontrolü yazılır.
if (env.equals("prod")) {
baseUrl = "https://fraud.company.com";
} else {
baseUrl = "http://localhost:9090";
}Doğru yaklaşım
Ortamdan gelen değerler typed configuration objesine bağlanır.
minibank:
fraud:
base-url: http://localhost:9090
timeout-ms: 1500MiniBank’ta transfer limiti, fraud kontrolünün açık/kapalı olması, external servis adresleri ve audit davranışları configuration ile yönetilecek. Böylece aynı kod dev ortamında rahat, prod ortamında kontrollü çalışabilecek.
7.2 application.yml nasıl düşünülmeli?
application.yml, Spring Boot uygulamasının varsayılan ayar dosyasıdır. YAML formatı, property’leri hiyerarşik yazmayı kolaylaştırır. Bu sayede birbiriyle ilişkili ayarlar tek bir namespace altında toplanabilir.
Senior seviyede önemli olan, dosyaya her şeyi doldurmak değil; ayarları okunabilir, domain’e yakın ve sürdürülebilir şekilde gruplamaktır. minibank.transfer.daily-limit gibi bir property, business anlamı olan bir ayardır. x.y.z.enabled gibi belirsiz isimler zamanla bakım maliyeti üretir.
server:
port: 8080
spring:
application:
name: minibank
minibank:
transfer:
daily-limit: 50000
currency: TRY
audit:
enabled: true
fraud:
enabled: true
base-url: http://localhost:9090
timeout-ms: 1500application.yml configuration merkezi olabilir ama secret merkezi olmamalıdır. Password, access token ve private key gibi değerler dosyaya yazılıp Git’e gönderilmemelidir.
7.3 Profile-based config nedir?
Profile, aynı uygulamanın farklı ortam davranışlarıyla çalışmasını sağlar. Örneğin local development sırasında fraud servisini mocklamak isteyebiliriz; production’da ise gerçek fraud servisine bağlanmalıyız. Bunu kodu değiştirerek değil, aktif profile göre config değiştirerek yaparız.
Spring Boot’ta yaygın kullanım şu şekildedir: ortak ayarlar application.yml içinde kalır; dev ortamına özel değerler application-dev.yml, prod ortamına özel değerler application-prod.yml içinde tutulur.
application.yml
Ortak ayarlar. Uygulama adı, default değerler, domain config namespace’leri.
application-dev.yml
Local geliştirme değerleri. Daha detaylı log, local servis URL, rahat limitler.
application-prod.yml
Production değerleri. Gerçek servis URL, daha kontrollü log, env var placeholder’ları.
# application-dev.yml
minibank:
transfer:
daily-limit: 100000
fraud:
enabled: false
base-url: http://localhost:9090
# application-prod.yml
minibank:
transfer:
daily-limit: 50000
fraud:
enabled: true
base-url: ${FRAUD_SERVICE_BASE_URL}
timeout-ms: 1000Aktif profile şu şekilde verilebilir:
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
# veya environment variable
SPRING_PROFILES_ACTIVE=prod java -jar minibank.jarProfile, “başka bir kod çalıştırayım” demek değildir. Aynı uygulamayı farklı ayarlarla çalıştırmaktır. Kod mümkün olduğunca aynı kalmalı; davranış configuration ile değişmelidir.
7.4 @ConfigurationProperties neden önemli?
Config değerlerini doğrudan @Value ile okumak küçük örneklerde kolay görünür. Fakat uygulama büyüdükçe aynı prefix altındaki değerler birçok class’a dağılır. Bu durumda hangi property’nin nerede kullanıldığı, default değerinin ne olduğu ve tipinin ne olması gerektiği belirsizleşir.
@ConfigurationProperties, bu değerleri Java class’ına bağlar. Böylece config bir string yığını olmaktan çıkar, uygulamanın bir parçası olan tip güvenli bir modele dönüşür.
@Value ile dağınık kullanım
@Service
public class TransferService {
@Value("${minibank.transfer.daily-limit}")
private BigDecimal dailyLimit;
}Property adı string olarak dağılır. Test etmek ve refactor etmek zorlaşır.
@ConfigurationProperties ile model
@ConfigurationProperties(prefix = "minibank.transfer")
public record TransferProperties(
BigDecimal dailyLimit,
String currency
) {}Ayarlar tek model altında toplanır. Constructor injection ile servislerde rahat kullanılır.
@Service
public class TransferLimitService {
private final TransferProperties transferProperties;
public TransferLimitService(TransferProperties transferProperties) {
this.transferProperties = transferProperties;
}
public boolean isWithinDailyLimit(BigDecimal amount) {
return amount.compareTo(transferProperties.dailyLimit()) <= 0;
}
}Typed configuration, sadece kod güzelliği değildir. Büyük ekiplerde property isimlerini, default davranışı ve ortam farklarını takip edilebilir hale getirir. Ayrıca testlerde configuration objesini doğrudan oluşturarak Spring context açmadan unit test yazabilirsin.
7.5 Environment variable ile override mantığı
Production ortamında config değerleri çoğu zaman dosyadan değil, deployment ortamından gelir. Container, Kubernetes, CI/CD pipeline veya secret manager bu değerleri environment variable olarak sağlayabilir.
Spring Boot relaxed binding mantığı sayesinde YAML içindeki minibank.fraud.base-url property’si environment variable olarak MINIBANK_FRAUD_BASE_URL şeklinde verilebilir.
export SPRING_PROFILES_ACTIVE=prod
export MINIBANK_FRAUD_BASE_URL=https://fraud-api.company.internal
export MINIBANK_FRAUD_TIMEOUT_MS=1000
java -jar minibank.jar7.6 Sensitive config yönetimi
Her configuration aynı hassasiyette değildir. Transfer limiti veya feature flag gibi değerler repo’da tutulabilir. Ancak database password, JWT secret, external API token veya private key gibi değerler Git’e girmemelidir.
Bu modülde secret manager entegrasyonuna girmeyeceğiz; fakat prensip net: secret değerleri kaynak kod deposunda değil, runtime ortamında sağlanmalıdır. Spring Boot tarafında bu değerler environment variable veya platform secret mekanizması üzerinden okunabilir.
Repo’da durabilir
- Feature flag default değeri
- Local dev base URL
- Business limit default değeri
- Log level default değeri
Repo’ya yazılmamalı
- Database password
- JWT signing secret
- External API token
- Private key / certificate secret
MiniBank Case 07 — Profile Based Configuration
Bu case’de MiniBank’ın dev/prod config ayrımını kuracağız ve transfer/fraud ayarlarını @ConfigurationProperties ile typed modele bağlayacağız. Amaç hata avlamak değil; doğru configuration yapısını birlikte inşa etmek. Görev listesi, doğrulama komutları, kod adımları ve kabul kriterleri Lab Dashboard'da.
Lab sırasında geride kalırsan lab-07-complete branch'ine geçip herkesle aynı checkpoint'ten devam edebilirsin.
Bu modülden akılda kalması gerekenler
Configuration, davranışı koddan ayırır.
Kodu yeniden build etmeden port, URL, limit, timeout ve feature flag gibi ayarları değiştirebilirsin.
Profile, aynı uygulamayı farklı ortam davranışlarıyla çalıştırır.
Dev ve prod ayrımı kod içinde if yazmak yerine configuration katmanında yönetilmelidir.
@ConfigurationProperties typed config sağlar.
Dağınık @Value kullanımı yerine domain’e yakın, okunabilir ve test edilebilir config modelleri oluşturur.
Environment variable production için kritik override mekanizmasıdır.
Deployment ortamı gerçek URL, secret ve limit değerlerini uygulamaya dışarıdan verebilir.
Secret değerleri repo’ya yazılmaz.
Database password, JWT secret ve API token gibi bilgiler runtime ortamından veya secret manager’dan gelmelidir.
5 soru ile hızlı kontrol
1. Configuration neden kodun içine yazılmamalıdır?
Çünkü ortam değiştikçe kodu değiştirmek ve yeniden build almak gerekir. Ayrıca secret ve ortam bağımlı değerler kod içinde tutulursa güvenlik ve bakım riski oluşur.
2. Profile ne işe yarar?
Aynı uygulamanın dev, test ve prod gibi farklı ortamlarda farklı ayarlarla çalışmasını sağlar.
3. @ConfigurationProperties ile @Value arasındaki temel fark nedir?
@Value tek tek property okur; @ConfigurationProperties ilişkili property’leri bir Java modeline bağlar ve daha sürdürülebilir bir yapı sağlar.
4. Environment variable ne zaman kullanılır?
Özellikle production deployment sırasında URL, timeout, secret veya profile gibi değerleri uygulama dışından vermek için kullanılır.
5. Secret değerler neden application.yml içine yazılmamalıdır?
Çünkü bu dosyalar genellikle Git reposunda tutulur. Secret değerlerin repo’ya girmesi güvenlik riski oluşturur.