[Spring] profile로 beta, real 빌드 구분하기
Spring profile VS Gradle(Maven) profile
Spring profile? :: @Profile()
- Spring profile은 빌드 결과물 내에서 스프링이 어떤 profile을 사용할지 선택하는 것
- 런타임 프로파일 설정
Gradle(Maven) profile?
- 빌드 시 어떤 profile을 리소스에 포함 시킬지 선택하는 것
- 빌드타임 프로파일 설정
- ≒ Maven profile
- 즉, Gradle profile이 더 큰 파일 개념이고, 선택한 파일(e.g., 리소스 파일)을 jar에 포함하거나 포함하지 않거나를 결정하는데 사용함.
- 예를 들어 alpha/resources.yml 파일을 패키징 시 jar에 포함 할거냐 말거냐.
-----
- profile 구분 없이, 어떤 프로파일이든 모든 리소스 파일이 jar 패키징 시 포함되어도 상관 없는 경우?
- [Spring profile만 사용]
- Spring profile만 사용했을 때의 장점은, 모든 리소스 파일이 jar에 들어있으니
- 프로파일 변경 시 굳이 빌드를 다시 할 필요가 없고
- 테스트 시 리소스 문제로 신경써야 하는 상황이 적음.
- 빌드 시 @ActiveProfiles로 테스트만 다른 프로파일 적용해서 돌린다거나. (이 경우 빌드 대상 프로파일과 테스트용 프로파일 리소스 둘 다 필요함)
- 근데 jar가 유출되면 뜯어서 리얼 서버에서 사용하는 Key 등등을 확인할 수 있다는 건 단점.
- 프로파일에 따라 jar에 포함되면 안되는 리소스가 존재하는 경우?
- [Gradle profile & Spring profile을 둘 다 사용]
- 어느 쪽으로 가든, Spring profile은 꼭 사용해야 한다.
- 공통으로 사용할 `` application.yml``을 하나 두고, 빌드 환경에 따라 추가적으로 `` application-${profile}.yml``을 불러오도록 구성하려면 Spring profile이 꼭 필요하다.
- 빌드시점에 Gradle profile로 `` application-${profile}.yml``을 포함하도록 하더라도, 스프링에서 여기있는 변수를 불러오는건 별개의 문제이기 때문
Gradle Profile 구성하기
build.gradle.kts
```kt
val profile = if (project.hasProperty("profile"))
project.property("profile").toString() else "local"
sourceSets {
main {
resources {
srcDirs(listOf("src/main/resources", "src/main/resources-$profile"))
}
}
}
// spring으로 넘어기는 프로파일은 $profile (@Profile 애너테이션 등에서 사용하게 될)
// 리소스를 불러오는 것은 resources-$environment 로 나누는 것도 필요하다면 가능하다.
```
- 여기서 주의할 점
- 같은 파일명의 `` application.yml``이 각 dir 마다 존재한다면, 가장 마지막에 명시된 dir의 `` application.yml``만을 사용하게 됨.
- 그래서 폴더를 `` resources``, `` resources-alpha`` 등으로 나누더라도 내부에 들어가는 파일 이름을 다르게 지정해 주어야 한다. (application-real.yml)
- 폴더를 `` resources``, `` resources-alpha`` 등으로 나누는 이유?
- 폴더 분리 안하고 `` resources/`` 하위에 `` application-beta.yml`` 등을 모두 함께 넣어버리면, 해당 dir의 모든 리소스가 같이 포함되어 jar로 묶인다.
- jar가 유출되면 뜯어서 리얼 서버에서 사용하는 Key 등등을 알아낼 수 있음.
- 따라서 폴더를 분리하여 필요한 리소스만 포함해서 빌드하도록 하는 것이 좋다.
srcDirs를 조절하거나, exclude 설정을 통해서 모두 resources 하위에 두는 것도 가능은 하지만 조금 번잡스럽다.
- 이런 식으로 위치시키고 빌드하면, `` resources/application.yml, resources-local/application-local.yml``이 포함되어 빌드된다
- 근데 막상 런타임에는 `` application-local.yml``에 있는 상수 이름은 못찾는다고 에러가 발생한다.
- Spring Profile을 설정해줘야 여기 있는 상수도 찾을 수 있음!
- 어떤 Spring profile을 빌드 시 포함하도록 할 것인지는 다음 옵션으로 지정
- `` gradle clean build -Pprofile=beta``
- intelliJ 에서는 Run Configurations에서
- Before launch - Run Gralde task
- Task : `` clean build``
- Arguments : `` -Pprofile=$profile``
- Before launch - Run Gralde task
Spring Profile 구성하기
https://www.baeldung.com/spring-profiles
application.yml
```
spring:
profiles:
active: local
```
- 이렇게 설정해줘야 `` application-local.yml``에 있는 상수도 불러올 수 있다.
- 스프링은 프로필로 설정된 문자열에 해당하는 `` application-${profile}.yml``가 있는지 뒤져보고, 있다면 불러온다.
- 이 경우 `` application-local.yml``이 있는지 찾아보고, 없으면 넘어가고 있다면 불러옴.
- 어떤 Spring profile을 사용할 것인지는 다음 세 가지 방법으로 설정 가능
- application.yml에 active로 명시
- argument로 전달
- RUN_ARGS : `` --spring.profiles.active=xx,yy``
- JAVA_OPTS(VM options) : `` -Dspring.profiles.active=xx,yy``
- 환경변수 : `` SPRING_PROFILES_ACTIVE=xx``로 명시
build.gradle.kts의 profile 변수를, gradle Task 실행 시 전달
- gradle_system_properties 란?
- 위에서 [argument로 전달:JAVA_OPTS] 부분을, build.gradle.kts에 명시해서 자동으로 넣어준다고 보면 될 것 같다.
```kt
// Test task를 실행할 때 profile 전달
tasks.getByName<Test>("test") {
systemProperty("spring.profiles.active", profile)
}
```
IntelliJ에서 실행할 때?
- intelliJ에서는 Run Configurations에서 다음 두 가지 모두 설정해줄 것.
- Active Profiles
- 이 설정은 launch하면서 쓰는 설정이다.
- clean build 라는 Gradle task를 실행하면서 적용되는 환경변수는 따로 설정해주어야 한다
- Gradle task(bootRun, Test, ...)를 실행할 때 선택할 profile 지정
- 방법1 ) 위의 build.gradle.kts의 profile 변수를 gradle Task 실행 시 전달
- 방법2 ) Before launch: Gradle task에 환경변수 명시
- Gradle task 실행시 선택할 profile을 명시 안하면 Test 돌릴 때 Profile이 default로 설정돼서 실패뜬다.
- Active Profiles
분명 모든 설정을 잘 했는데 안될 때... 빌드 결과물 resource 확인해보면 프로파일이 제대로 적용되지 않은 경우가 종종 있음
IntelliJ 오류로 언제는 되고 언제는 안되고 그럴 수 있어서 확인 필요.
반대로 application-core.yml을 구성하는 방법은?
- [1] 위 방식은 공통으로 사용할 `` resources/application.yml``과 선택에 따라 `` resources-${profile}/application-${profile}.yml``을 불러오는 방법.
- [2] 반대로 공통으로 사용할 `` resources/application-core.yml``을 두고, 선택에 따라 `` resources-${profile}/application.yml``을 불러오도록 하는 방법도 있다.
- 어느 쪽이 되었건 `` application.yml``이 먼저 로드되고, `` application-xxx.yml``이 더 늦게 로드 된다.
- 같은 이름 상수가 정의되어 있는 경우, 늦게 로드 되는 쪽이 overwrite 한다!
- 그래서 [1] 방식을 사용하는 편이 좋아 보인다. 실수로 같은 이름 상수를 정의한 경우에도, 더 specific한 설정으로 덮어 써지므로.
test property 설정 예제
- test/resources에 있는 것은 이걸 사용하고, 없는 것은 main/resources 사용하고 싶은 경우?
- 별도 설정 필요 없음. 자동으로 이렇게 되어 있음.
```
target // 빌드 결과 dir
ㄴ classes // 2. 1번에서 없으면 여기 리소스를 뒤진다.
ㄴ test-classes // 1. 테스트 시 여기 리소스를 먼저 뒤지고
```
```bash
// 실행 커맨드에 spring profile 옵션도 주어야 함. 아니면 .properties 파일에서 maven profile을 @variable@ 형태로 넘겨받는 방법도 있긴 한데. spring default profile 지정과 둘 중 하나는 포기해야 하므로... 직접 명시하는게 나은 듯.
$ mvn clean test -P test -Dspring.profiles.active=test
// 참고로 install 시 테스트 스킵하는 옵션은
$ mvn clean install -P beta -Dmaven.test.skip=true
```
참고
https://perfectacle.github.io/2017/09/23/Spring-boot-gradle-profile/
'Java Stack > Spring' 카테고리의 다른 글
Java Servlet 이란 (0) | 2020.06.15 |
---|---|
RestTemplate은 어떻게 response Object를 DataType <T>로 변환하는가 (0) | 2020.03.27 |
[Spring] Controller에서 사용하는 애너테이션 (0) | 2019.09.25 |
Spring AOP / @annotation resolve (0) | 2019.07.30 |
Hystrix with Spring ( Circuit Breaker ) 를 사용할 때 주의해야 할 점. (0) | 2019.07.30 |
댓글
이 글 공유하기
다른 글
-
Java Servlet 이란
Java Servlet 이란
2020.06.15 -
RestTemplate은 어떻게 response Object를 DataType <T>로 변환하는가
RestTemplate은 어떻게 response Object를 DataType <T>로 변환하는가
2020.03.27 -
[Spring] Controller에서 사용하는 애너테이션
[Spring] Controller에서 사용하는 애너테이션
2019.09.25 -
Spring AOP / @annotation resolve
Spring AOP / @annotation resolve
2019.07.30