leelee.log
[Spring] profile 과 properties 본문
intellij로 spring boot 프로젝트를 만들면 꼭 같이 만들어지는 파일이 하나 있다. 바로 application.properties라는 파일인데 처음에는 db의 url과 아이디/비밀번호를 써서 db 연결에만 사용하고 있었지만 요즘은 프로젝트에서 사용되는 전역적인 정보들을 기록해둬서 @Value 어노테이션으로 값을 빼와 코드에 사용하고는 한다. 여기서의 전역적인 정보들은 보통 1. 사용하는 api key 2. port와 context-path 3. 파일이 업로드 될 주소 가 등 이 있다.
profile 과 properties의 차이를 처음에는 헷갈려 했는데 강의를 다 듣고 나니 properties는 key-value 쌍의 정보고, 그 properties가 모여있는 하나의 파일을 profile이라고 이해 했다. 아까 말한 application.properties말고도 여러가지 환경을 조성하기 위해 다양한 properties 파일을 만들 수 있다. 예를 들어 코드를 작성하면 여러 단계를 거쳐서 배포를 하게 되는데 test 환경을 위한 properties나 test와 유사한 dev 환경을 위한 properties, 유저들에게 실사용 되는 상용 환경을 위한 prod properties 등으로 나눠서 환경을 조성할 수 있다. 만약 아무런 profile 설정을 안 해준다면 default 환경인 application.properties가 사용될 것이다.
그럼 이렇게 profile을 나누는 이유는 무엇일까? 또 다시 예를 들어보자면 개발을 하면서 개발자들은 바로 상용으로 배포하지 않고 여러번의 test를 거친다는 건 이미 잘 알려진 사실이다. 만약 게시판 같은 서비스를 만들고 테스트를 하기 위해서는 유저의 정보, 게시판 글 정보 등을 저장해둔 db가 필요하다. 그런데 상용에서 사용하는 db를 이용해서 테스트를 진행하는 것 보다는 test만을 위한 db를 파서 그 db를 사용하는게 더 좋을 것이다. 그럼 test에서는 test db에 연결을 해줘야 하고 상용인 prod에서는 prod db를 연결해줘야 한다. 이 번거로운 구분 작업을 profile만 설정해두면 spring이 알아서 해준다.
여태 profile 세팅을 바꿔줄 일이 있으면 edit configuration창에서 vm option에 -Dspring.profiles.active=test 처럼 해당 환경의 properties 파일 이름을 넣어줬었는데 밑에있는 Active profiles에 test 라고 적어주기만 해도 가능하다고 한다. 그리고 몇가지 방법을 더 배웠는데 그 전에 내가 했던 실수에 대해 말을 하고자 한다.
회사에서 application-test.properties, application-prod.properties 라는 형식으로 properties를 사용해서 예제를 만들때도 똑같이 application-test.properties라고 쓰고 vm option에 -Dspring.profiles.active=tet 라고 명시를 했는데도 계속 default properties가 사용이 되어 결국 test.properties 라는 파일을 하나 더 만들어서 사용을 했다. 알고보니 application-test.properties를 test 환경을 위한 profile이라고 하고 싶었다면 application-test.properties 파일에 spring.profiles.active=test 라고 따로 명시를 해줬어야 했다. 그냥 test.properties 파일을 만들었을 때는 spring이 알아서 이 파일은 test profile이라고 인식하기 때문에 추가 작업을 할 필요가 없다.
ApplicationContext를 여태 IoC Container에 접근할 수 있는 객체라고만 생각을 했는데 사실은 spring의 environment 에도 접근을 할 수 있었다. ApplicationContext.getEnvironment.getActiveProfiles() 로 현재 적용된 profile을 가져오는 것도 놀라웠지만 Application.Context.getEnviroment.getProperty("property 이름")으로 해당 profile에 선언된 property 를 가져오는게 특히 놀라웠다. 예를 들어 내가 test.properties 파일에 spring.test.name=Jamie 라고 써뒀다면 Application.Context.getEnvironment.getProperty("spring.test.name")으로 Jamie 값을 뽑아 올 수 있다. 내가 사용하는 다른 방법으로는 @Value("${spring.test.name}") 이 있는데 이건 개발자가 원하는 방식대로 쓰면 될 것 같다.
profile에 따른 설정을 properties 값만 다르게 들어오는 것만 해봤지 @Profile 어노테이션을 써서 Bean을 특정 profile 환경일때만 만들어지게 하는 걸 해본적이 없는데 나중에는 쓸 일이 있을 것 같다. @Configuration 에 @Profile을 줘서 특정 환경에서만 저 Configuration 파일에 선언해둔 bean을 만드는 것도 굉장히 신기했다. @Profile 어노테이션에서는 not, or, and 연산자인 ! & | 이 사용이 가능해서 이것저것 조합해서 profile을 적용시킬 수 있는데 강의에서 어지간하면 복잡하게 설정을 하지 말고 간단하게 Profile을 설정하는게 좋다고 한다...
properties에 대한 얘기를 조금 더 해보자면 아까 말한 것 처럼 key-value의 쌍으로 되어있는 계층형 데이터이다. 무슨 말이냐면 spring.test.name=Jamie 라고 선언을 하면 spring.test.name은 key가 되는 것이고 Jamie는 value가 된다. 여기서 게층형이라는 단어가 나오니 새로울 수 있는데 이건 profile 세팅을 spring의 여러 부분에서 했다면 순위가 제일 높은 부분의 세팅을 따라간다는 소리다.
Spring 에서 아까 말한 edit configuration에서 vm option을 주는 것 말고도 @SpringBootApplication 어노테이션 밑에 @PropertySource("classpath:/application-test.properties") 을 사용해서 profile를 설정해줄 수 있는데 @PropertySource에서 test1 로 profile 환경을 설정하고 vm option에서 test2 로 profile 환경을 설정해주면 test2로 환경설정이 된다. vm option이 더 높은 계층이기 때문이다.
테스트가 안되서 물을 먹었는데 만약에 defualt propertis 파일에서만 선언을 해두고 다른 propertis에는 선언해두지 않은 properties가 있다면 자동으로 상속이 된다. 예를 들어 application.propertis에서 spring.app.value=12 라고 선언을 해두고 test.application에서 선언을 해두지 않고 바로 test profile을 적용하면 spring.app.value 를 꺼내올 때 자동으로 application.properties에 있는 spring.app.value인 12 를 꺼내오게 된다.
이런 기능은 당연히 최상위-하위 관계에서만 일어나고 하위-최상위 관계에서는 일어나지 않는다.
'개발 > Backend' 카테고리의 다른 글
[Spring] (en) How to deal with SQL exception in Spring boot (0) | 2023.04.18 |
---|---|
[Spring] Resource를 가져오는 방법 (0) | 2020.05.24 |
[Spring] Bean Scope (0) | 2020.03.31 |
[Spring] @Primary, @qualifier (0) | 2020.03.18 |
[Spring] @SpringBootApplication과 @ComponentScan (0) | 2020.03.17 |