Gün 2 / Web Layer & Runtime / Modül 07 — Configuration & Profiles
Ana Portal
Modül 07 Gün 2 Runtime Behavior ~75 dk

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.

Anlatım
45 dk
MiniBank Case
30 dk
Kapanış
5 dk
Checkpoint
lab-07

Kodu değiştirmeden uygulamanın davranışını güvenli şekilde yönetebileceksin.

01

Config mantığını oturtacaksın

Hangi bilgi kodda kalmalı, hangi bilgi configuration’a taşınmalı ayrımını netleştireceksin.

02

Profile bazlı davranış kuracaksın

Dev, test ve prod için farklı ayarları aynı uygulama koduyla yönetmeyi göreceksin.

03

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.

Hard-coded config
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.

Typed config
minibank:
  fraud:
    base-url: http://localhost:9090
    timeout-ms: 1500
MiniBank bağlantısı

MiniBank’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.

application.yml — okunabilir config yapısı
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: 1500
Dikkat

application.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.

base

application.yml

Ortak ayarlar. Uygulama adı, default değerler, domain config namespace’leri.

dev

application-dev.yml

Local geliştirme değerleri. Daha detaylı log, local servis URL, rahat limitler.

prod

application-prod.yml

Production değerleri. Gerçek servis URL, daha kontrollü log, env var placeholder’ları.

Profile dosya örnekleri
# 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: 1000

Aktif profile şu şekilde verilebilir:

Profile aktifleştirme
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev

# veya environment variable
SPRING_PROFILES_ACTIVE=prod java -jar minibank.jar
Mental model

Profile, “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

kaçınılacak yaklaşı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

önerilen yaklaşım
@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.

TransferService içinde typed config kullanımı
@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;
    }
}
Senior farkı

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.

01
Default değer
application.yml içinde güvenli veya local default bulunur.
02
Profile değeri
application-prod.yml bazı değerleri override eder.
03
Env var
Deployment sırasında gerçek değer dışarıdan verilir.
04
Runtime
Uygulama effective configuration ile çalışır.
Environment variable örneği
export SPRING_PROFILES_ACTIVE=prod
export MINIBANK_FRAUD_BASE_URL=https://fraud-api.company.internal
export MINIBANK_FRAUD_TIMEOUT_MS=1000

java -jar minibank.jar

7.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.

Başlangıç
lab-07-start
Tamamlanmış
lab-07-complete
Checkpoint kuralı

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

1

Configuration, davranışı koddan ayırır.

Kodu yeniden build etmeden port, URL, limit, timeout ve feature flag gibi ayarları değiştirebilirsin.

2

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.

3

@ConfigurationProperties typed config sağlar.

Dağınık @Value kullanımı yerine domain’e yakın, okunabilir ve test edilebilir config modelleri oluşturur.

4

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.

5

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.