자바 백엔드 입문 13편 — application.yml Spring Profiles

2026-05-17자바 백엔드 입문

자바 백엔드 입문 13편. dev·staging·prod 환경별 설정을 분리하는 Spring Profiles와 application.yml 계층 구조, @Value·@ConfigurationProperties 외부화까지 풀어쓴 학습 노트.

📚 자바 백엔드 입문 · 13편 — application.yml Spring Profiles

이 글은 자바 백엔드 입문 시리즈 59편 중 13편이에요. "개발할 땐 H2, 운영은 PostgreSQL", "개발 로그는 DEBUG, 운영은 INFO" — 환경별 설정 분리를 풀어 가요.

환경 설정이 헷갈리는 이유

처음 Spring Boot를 배우면 — application.properties·application.yml·@Value·@ConfigurationProperties·@Profile·application-dev.yml 같은 단어가 한꺼번에 쏟아져요. 무엇이 무엇을 덮어쓰는지 안 잡혀요.

이 글에서는 여행 가방 비유로 풀어요. application.yml = "공통 짐", application-dev.yml = "국내 여행용 추가 짐", application-prod.yml = "해외 여행용 추가 짐". 환경별로 추가 짐만 바꿔 끼움.

application.properties vs application.yml

두 가지 형식 다 지원. 같은 설정.

# application.properties
server.port=8080
spring.datasource.url=jdbc:postgresql://localhost:5432/myshop
spring.jpa.hibernate.ddl-auto=validate
# application.yml
server:
  port: 8080
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/myshop
  jpa:
    hibernate:
      ddl-auto: validate

YAML이 가독성 우수 — 계층 구조가 자연스럽게 표현돼요. 신규 프로젝트 거의 100% YAML.

Profile 기본 — application-{profile}.yml

src/main/resources/ 안에 환경별 파일 분리.

application.yml              # 공통
application-dev.yml          # 개발
application-staging.yml      # 스테이징
application-prod.yml         # 운영

활성화는 spring.profiles.active 한 줄.

# application.yml (공통)
spring:
  application:
    name: myshop
  profiles:
    active: dev          # 기본 활성 프로파일

또는 실행 시 환경 변수·인자.

# 명령줄
java -jar myshop.jar --spring.profiles.active=prod

# 환경 변수
SPRING_PROFILES_ACTIVE=prod java -jar myshop.jar

환경별 설정 예

# application.yml (공통)
spring:
  application:
    name: myshop
  jpa:
    open-in-view: false
server:
  port: 8080
# application-dev.yml
spring:
  datasource:
    url: jdbc:h2:mem:devdb
    driver-class-name: org.h2.Driver
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true
logging:
  level:
    com.example.myshop: DEBUG
# application-prod.yml
spring:
  datasource:
    url: jdbc:postgresql://prod-db.example.com:5432/myshop
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  jpa:
    hibernate:
      ddl-auto: validate
    show-sql: false
logging:
  level:
    com.example.myshop: INFO
    org.hibernate.SQL: WARN

우선순위application-prod.yml 값이 application.yml 값을 덮어씀. prod 활성 시 두 파일이 합쳐져 동작.

${ENV} — 환경 변수 참조

비밀번호·API 키 같은 민감 정보는 코드에 박지 않고 환경 변수로.

spring:
  datasource:
    password: ${DB_PASSWORD}                 # 환경 변수 필수
    username: ${DB_USERNAME:postgres}        # 없으면 기본값 'postgres'

운영 환경 = Docker·Kubernetes의 secret에서 주입. 절대 git에 비밀번호 박지 X.

@Value로 설정값 주입

22편 SpEL 에서 다룬 패턴. application.yml 값을 자바 필드로.

app:
  upload-dir: /var/uploads
  max-file-size: 10485760
  welcome-message: "Hello Spring"
@Component
public class UploadConfig {

    @Value("${app.upload-dir}")
    private String uploadDir;

    @Value("${app.max-file-size:10485760}")     // 기본값 10MB
    private long maxFileSize;
}

@ConfigurationProperties — 객체로 묶기

여러 설정을 한 객체로 묶을 때 더 깔끔. 회사 시스템 표준.

app:
  upload:
    dir: /var/uploads
    max-file-size: 10485760
    allowed-types:
      - image/jpeg
      - image/png
    s3:
      bucket: my-uploads
      region: ap-northeast-2
@Configuration
@ConfigurationProperties(prefix = "app.upload")
@Getter @Setter
public class UploadProperties {
    private String dir;
    private long maxFileSize;
    private List<String> allowedTypes;
    private S3Properties s3;

    @Getter @Setter
    public static class S3Properties {
        private String bucket;
        private String region;
    }
}

이 한 클래스를 다른 Bean에서 주입받아 사용.

@Service
@RequiredArgsConstructor
public class UploadService {
    private final UploadProperties props;

    public void upload(MultipartFile file) {
        if (file.getSize() > props.getMaxFileSize()) throw ...;
        // ...
    }
}

@ConfigurationProperties 의 장점: - 타입 안전 — String이 아니라 정확한 타입 (long·List·중첩 객체) - 검증@Valid 박으면 @NotNull·@Min 같이 검증 가능 - 자동완성 — IDE 지원 (spring-boot-configuration-processor) - 여러 설정 묶기 — 응집도 높음

@Value vs @ConfigurationProperties — 한 개 값은 @Value, 여러 개 묶음 = @ConfigurationProperties 표준.

@Profile — 환경별 Bean 활성

특정 Bean을 "prod 환경에서만" 동작시킬 때 @Profile.

@Configuration
@Profile("prod")                                  // prod 환경에서만 등록
public class ProdEmailConfig {
    @Bean public EmailSender realEmailSender() { ... }
}

@Configuration
@Profile({"dev", "test"})                          // dev 또는 test
public class DevEmailConfig {
    @Bean public EmailSender mockEmailSender() { ... }
}

@Configuration
@Profile("!prod")                                  // prod 아닐 때
public class DevToolsConfig { ... }

진짜 SMS·이메일 발송은 prod에만, 개발에서는 콘솔 출력 같은 가짜 구현.

외부 설정 우선순위

Spring Boot는 여러 곳에서 설정값을 읽어 우선순위로 머지.

1. 명령줄 인자 (--key=value) ← 최우선
2. 환경 변수 (SPRING_DATASOURCE_URL)
3. application-{profile}.yml
4. application.yml
5. @PropertySource 어노테이션
6. 기본값 (@Value의 :default)  ← 최하위

운영 환경에서 "비밀번호는 환경 변수로 박고, 나머지는 yml 파일" 흐름. 보안·유연성.

🎯 회사 시스템 표준 패턴

application.yml 에 공통 설정 + 비밀 아닌 환경별 차이 application-{profile}.yml 에. 비밀번호·API 키는 환경 변수 + Vault·Kubernetes Secret. Git에 비밀 절대 X.

한 줄 정리 — application.yml 공통 + application-{profile}.yml 환경별. SPRING_PROFILES_ACTIVE 로 활성. 비밀은 ${ENV} 환경 변수. 여러 설정 묶기는 @ConfigurationProperties, 단일 값은 @Value.

시험 직전 한 번 더 — Profiles 입문자가 매번 헷갈리는 것

  • application.yml = 공통 설정 (or application.properties)
  • application-{profile}.yml = 환경별 설정 (dev·staging·prod)
  • 활성 = spring.profiles.active 또는 환경 변수 SPRING_PROFILES_ACTIVE
  • 우선순위 = application-prod.yml > application.yml
  • ${ENV_VAR} = 환경 변수 참조
  • ${KEY:default} = 기본값 설정
  • @Value("${key}") = 단일 값 주입
  • @ConfigurationProperties(prefix = "...") = 묶음 객체 (권장)
  • @ConfigurationProperties 장점 = 타입 안전·검증·자동완성·응집도
  • @Valid 박으면 Bean Validation 자동 적용
  • @Profile("prod") = 환경별 Bean 활성
  • @Profile("!prod") = prod 아닐 때
  • 외부 설정 우선순위 = 명령줄 > 환경 변수 > yml > 기본값
  • 비밀번호 = 환경 변수 + Vault·Secret 표준
  • git에 비밀 박지 X (.gitignore)
  • YAML 들여쓰기 = 스페이스, 탭 X
  • 여러 줄 문자열 = | 또는 > 표기
  • 리스트 = - 또는 [a, b, c]
  • 자동완성 = spring-boot-configuration-processor 의존성
  • application-test.yml = 테스트 전용 (33편 참조)

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!