엄범

 

[Spring] 외부 상수 넣어주기

 

Spring profile VS Gradle profile
  • Spring profile? ``kt @Profile()``
    • Spring profile은 빌드 결과물 내에서 스프링이 어떤 profile을 사용할지 선택하는 것
    • 런타임 프로파일 설정
  • Gradle profile? `` .properties, .yml``
    • 빌드 시 어떤 profile을 리소스에 포함 시킬지 선택하는 것
    • 빌드타임 프로파일 설정
    • Maven profile
  • 즉, Gradle profile이 더 큰 파일 개념이고, 선택한 파일 이외는 jar에 포함하지 않을 수 있음.
  • Spring profile의 장점은 아예 빈 자체를 특정 프로파일에만 활성화 하는 등 좀 더 유연하게 사용할 수 있다는 점
    • 근데 해당 파일의 profile이 모두 jar에 포함된다는건 단점.
    • jar가 유출되면 뜯어서 리얼 서버에서 사용하는 Key 등등을 확인할 수 있으니까
  • 그래서 Gradle 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"))
        }
    }
}

```

  • 여기서 주의할 점
    • 같은 파일명의 `` application.yml``이 각 dir 마다 존재한다면, 가장 마지막에 명시된 dir의 `` application.yml``만을 사용하게 됨.
    • 그래서 폴더를 `` resources``, `` resources-alpha`` 등으로 나누더라도 내부에 들어가는 파일 이름을 다르게 지정해 주어야 한다.
  • 폴더를 `` resources``, `` resources-alpha`` 등으로 나누는 이유?
    • 폴더 분리 안하고 `` resources/`` 하위에 `` application-beta.yml`` 등을 모두 함께 넣어버리면, 해당 dir의 모든 리소스가 같이 포함되어 jar로 묶인다.
    • jar가 유출되면 뜯어서 리얼 서버에서 사용하는 Key 등등을 알아낼 수 있음.
    • 따라서 폴더를 분리하여 필요한 리소스만 포함해서 빌드하도록 하는 것이 좋다.

  • 이런 식으로 위치시키고 빌드하면, `` 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``

 

Spring Profile 구성하기

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 : `` -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로 설정돼서 실패뜬다.

 

반대로 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한 설정으로 덮어 써지므로.

 

참고

https://garyj.tistory.com/9  

https://perfectacle.github.io/2017/09/23/Spring-boot-gradle-profile/