자바 백엔드 입문 13편. dev·staging·prod 환경별 설정을 분리하는 Spring Profiles와 application.yml 계층 구조, @Value·@ConfigurationProperties 외부화까지 풀어쓴 학습 노트.
이 글은 자바 백엔드 입문 시리즈 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= 공통 설정 (orapplication.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편 참조)
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
- 8편 — 자바 Optional null 안전
- 9편 — 자바 Stream API 람다
- 10편 — Maven·Gradle 의존성 관리
- 11편 — Spring Framework란
- 12편 — start.spring.io 첫 프로젝트
다음 글: