Profile이 필요한 이유
실제 회사(현업)에서 개발을 할 때엔 N개의 Profile을 설정한다. (ex. local, dev, test, prod 등)
Profile을 나누는 이유는 환경별로 설정해야 하는 Property 값들이 다르기 때문이다.
더불어 만약 환경별로 로깅 레벨을 다르게 두고 싶을 때 어떻게 해야할까?
이 때 profile을 사용하여 손쉽게 애플리케이션 동작을 조정할 수 있기에 profile을 알아둘 필요가 있다.
Spring Profiles
Spring Profiles는 애플리케이션 구성의 일부를 분리하고 특정 환경에서만 사용할 수 있도록 방법을 제공한다.
예를 들어, 개발 환경에서만 사용할 수 있는 Bean이 있고, 프로덕션용 Bean이 있을 수 있다.
Profile을 사용하면 특정 환경(ex. dev, test, prod 등)에만 적용되는 Bean을 정의하여 현재 환경에 따라 적절한 구성 요소만 로드되도록 할 수 있다.
Profile 사용 예시
Profile 사용은 다음과 같은 경우에 유용하다.
다양한 환경(dev, test, prod 등 환경을 위한 다양한 데이터베이스 구성)에 적용해야 하는 구성을 구별
application-local.yml, application-prod.yml 2개의 파일이 있을 때,
JVM 시스템 속성 사용 (Dspring.profiles.active)
애플리케이션을 실행할 때 -D 옵션을 사용하여 활성화할 profile을 지정
Dspring.profiles.active은 애플리케이션 context에 대해 "활성"으로 인식해야하는 Spring profile을 지정하는 JVM 시스템 속성이다. 이 속성을 설정하는 것은 특정 profile을 활성화하는 방법 중 하나다.
java -Dspring.profiles.active=prod -jar my-application.jar
위 예시 명령은 "prod" profile을 활성화하고 @Profile("prod") 주석이 표시된 Bean 및 구성만 로드된다.
즉, Spring profile과 Dspring.profiles.active 시스템 속성은 코드를 변경하지 않고도 애플리케이션이 다양한 환경에서 작동하는 방식을 제어할 수 있는 방법을 제공한다.
이러한 기능을 활용하면 개발, 테스트, 준비 및 프로덕션 환경에 맞게 애플리케이션 동작을 조정할 수 있다.
환경 변수 사용
환경 변수를 설정하여 활성화할 profile을 지정
export SPRING_PROFILES_ACTIVE=prod
java -jar your-application.jar
application.yml 에서 직접 설정 (유연성이 낮아서 추천X)
spring:
profiles:
active: local
조건부로 기능을 활성화 또는 비활성화
@Service
@RequiredArgsConstructor
public class DemoService {
@Value("${profile-name}")
private String name;
private final CommonDemoService commonDemoService;
private final MemberRepository memberRepository;
public String save() {
System.out.println("name = " + name);
if (name.equals("local")) {
System.out.println("local");
// local code
} else if (name.equals("prod")) {
System.out.println("prod");
// prod code
}
}
}
@Service
@Profile({"dev", "test"})
public class BetaFeatureService {
public String getFeature() {
return "Beta feature is enabled";
}
}
@Service
@Profile("!prod") // Exclude production
public class ExperimentalFeatureService {
public String getFeature() {
return "Experimental feature is enabled";
}
}
환경별 Property 값 사용
우선 profile을 적용해보기 위해 환경별로 나눠보자!
application-prod.yml
profile-name: prod
application-local.yml
profile-name: local
각각의 yml 파일에 profile-name으로 환경별 속성 값을 주었다.
DemoService
@Service
@RequiredArgsConstructor
public class DemoService {
@Value("${profile-name}")
private String name;
private final MemberRepository memberRepository;
public String save() {
System.out.println("name = " + name);
...
}
}
그리고 그걸 service에서 출력하도록 했다.
실행하면 도중에 서버를 띄우지 못하는데,
이유는 resource 디렉토리를 보면 아직 특별한 profile을 설정하지 않은 상태에서 스프링은 default profile로 동작하려고 하는데 profile의 기본 값인 application.yml이 없기 때문이다.
Intellij 실행 시 Profile 적용하는 방법
그러면 인텔리제이에선 어떻게 profile을 설정할 수 있는지 알아보자
간단하게 인텔리제이에선 구성 편집 -> active profile(활성화된 프로파일)을 통해 활성화할 프로파일을 적용할 수 있다.
적용 후 다시 실행하고 /save에 요청을 해보면
profile-name 값인 local이 출력되는 걸 확인할 수 있다.
Jar 실행 시 JVM 옵션으로 Profile 적용
실제 운영 서버에서는 앞서 말했듯 Jar 파일을 사용해서 서버를 실행시킨다.
이 때 java의 jvm 옵션을 통해 어떻게 하면 프로파일 값을 설정해 줄 수 있는지 알아보자
빌드 후 build/libs 에서
java -jar -Dspring.profiles.active=local module-api-0.0.1-SNAPSHOT.jar
Error: Unable to access jarfile .profiles.active=local 에러 발생하면? "" 쌍따옴표로 감싼다.
java -jar "-Dspring.profiles.active=local" module-api-0.0.1-SNAPSHOT.jar
정리
로컬 개발 설정, 테스트 단계, 프로덕션 시스템 등 다양한 환경에서 애플리케이션을 개발하고 배포하는 과정에서 Spring Profiles는 코드베이스를 변경하지 않고 애플리케이션 동작을 원활하게 조정할 수 있게 해준다.
Spring Profiles의 본질은 각 환경과 관련된 특정 구성, Bean 및 속성을 활성화하는 기능에 있으며, 이러한 유연성은 편리함일 뿐만 아니라 최신 애플리케이션 개발 및 배포 방식에 있어 필수라 생각한다.
Spring Profile이 중요한 이유는
- 구성 구별: 데이터베이스 설정과 같은 환경별 구성을 정의하여 애플리케이션이 활성 프로필(예: 'local', 'dev', 'test', 'prod')을 기반으로 적절한 리소스에 연결되도록 한다.).
- 조건부 기능 활성화: 환경에 따라 특정 기능이나 서비스를 활성화 또는 비활성화하여 보안을 강화하고 리소스를 최적화한다.
- A/B 테스트 촉진: 다양한 프로필에서 기능이나 서비스의 다양한 구현을 배포하여 A/B 테스트를 효율적으로 수행한다.
Spring Profile을 활용하는 방법은
- JVM 시스템 속성 사용: 애플리케이션을 실행할 때 '-Dspring.profiles.active=profile-name'을 지정하여 Profile을 활성화하면 코드를 변경하지 않고도 Profile을 전환할 수 있는 유연성을 얻을 수 있다.
- 환경 변수 설정: 애플리케이션 및 배포 환경에 맞는 환경 변수를 Profile을 통해 설정할 수 있다.
- 구성 파일: Profile별 애플리케이션 속성 또는 YML 파일(예: application-local.yml, application-prod.yml)을 활용하여 구성 값을 구성을 단순화한다.
'Spring' 카테고리의 다른 글
[Spring] 비동기 프로그래밍 - ThreadPoolExcutor (0) | 2024.04.13 |
---|---|
[Spring] 스프링 부트 예외 처리(2) - @ControllerAdvice, @ExceptionHandler (feat. 프로젝트에 맞는 CustomException 만들고 처리하기) (0) | 2024.04.12 |
[Spring] 스프링 부트 예외 처리(1) - API Error Code 적용하기 (feat. API 공통 스펙) (0) | 2024.04.12 |
[Spring] ObjectMapper 커스텀해서 사용해보기 (feat. serialization) (0) | 2024.03.20 |
[Spring] Swagger (0) | 2024.03.19 |