2020. 5. 29. 16:21ㆍSpring/Basic
웹 애플리케이션의 실행 환경에 따른 구성설정의 외부화를 위해 프로퍼티 파일을 사용했습니다.
spring boot에는 예약된 프로퍼티 키가 존재하며, 예약된 프로퍼티에 설정을 추가하는 것 만으로도 자동으로 설정을 대신해준다고 했었습니다.
spring boot에서 예약된 프로퍼티 키를 이용하는 것 외에도 우리가 직접 프로퍼티를 설정하고 설정한 값을 이용할 수 있습니다.
별도로 추가한 프로퍼티가 많아질 경우에는 파일이 매우 복잡해질수도 있고, 프로퍼티를 확인하것도 불편해질 것입니다.
이에 대한 해결책으로 이번 시간에는 프로퍼티 파일을 여러개 설정하고 웹애플리케이션의 시작시 자동으로 읽어들이는 방법을 알아볼 것입니다.
- 코드분리
- 테스트 API
- Spring Boot 2.4 미만 버전
- 구성파일 위치 설정
- 테스트
- Spring Boot 2.4 이상 버전
- 결론
※ Spring Boot Tutorial의 demo 프로젝트를 이용해서 실습합니다.
1. 코드 분리
spring boot에서 예약된 프로퍼티키는 application.yml
에 설정하고,
나머지 커스텀 프로퍼티는 demo.yml
에 설정합니다.
demo: api: /api/v1 test: userId: demo123 password: "demo123!" sites: - demo.jiniworld.me - api.jiniworld.me option: admin: true view: false
demo.yml
demo.yml
에 직접 생성한 프로퍼티 값을 설정합니다.
이전 시간에 만들었던 demo.api 프로퍼티도 demo.yml로 옮깁니다.
2. 테스트 API
프로퍼티값은 @ConfigurationProperties
나 @Value
를 이용하여 자바 코드에서 읽을 수 있습니다.
@ConfigurationProperties 는 하위 프로퍼티를 한꺼번에 읽을 때 사용하고, @Value는 하나의 프로퍼티를 읽을 때 사용합니다.
demo.test
하위 프로퍼티는 @ConfigurationProperties로, demo.api
는 @Value로 읽어봅시다.
@ToString @Setter @ConfigurationProperties(prefix = "demo.test") @Configuration public class TestConfig { private String userId; private String password; private List<String> sites; private Option option; @ToString @Setter public static class Option { private boolean admin; private boolean view; } }
demo.test
하위 프로퍼티를 읽기 위해 TestConfig 클래스를 추가했습니다.
@ConfigurationProperties를 이용하여 프로퍼티를 가져올 때, setter 메서드는 필수적으로 필요합니다.(ln 2, ln 13)
@RequestMapping(value = "/test") @RequiredArgsConstructor @RestController public class TestController { private final TestConfig testConfig; @GetMapping("/config") public Object testConfig(@Value("${demo.api}") String demoApi) { return String.format("%s\n%s", demoApi, testConfig); } }
테스트를 위한 GET API를 추가합니다.
@Value 로 demo.api
프로퍼티를 읽습니다. (@Value는 ${} 를 씌워야합니다.)
API를 추가했으니 웹 애플리케이션을 실행해봅시다.
그런데, 웹 애플리케이션 시작 중 에러가 발생되네요.
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'demo.api' in value "${demo.api}/users" at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:178) at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124) at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:237)
${demo.api}
를 읽어들일 수 없다는 에러입니다.
이는 demo 애플리케이션 api의 prefix에 demo.api
프로퍼티를 설정했는데, 현재 프로퍼티를 찾을 수 없어 url매핑이 되지 않아 발생된 에러입니다.
※ REST API Versioning 참고
말하자면, demo.yml을 웹 애플리케이션에서 인식하지 못했다는 의미인데요. demo.yml을 application.yml과 동일한 위치에 위치시킨다고 자동으로 파일을 인식하지 않으며 별도의 설정을 추가해야만 구성파일로 인식할 수 있기 때문입니다.
demo.yml 파일을 인식할 수 있도록 설정하는 방법을 알아봅시다.
3. 구성파일 위치 설정
spring boot 웹 애플리케이션에서는 application.yml을 자동으로 인식하여 프로퍼티 값을 로드합니다.
만일 기본적으로 설정되어있는 application.yml 이 아닌 다른 구성파일을 이용하려면(이름이 다르거나, 여러개의 구성파일을 이용하거나) 별도의 설정을 해야합니다.
만일 다른이름의 구성파일을 이용하고 싶다면 spring.config.name
로 구성파일의 이름을 설정해야하며, 여러개의 구성파일을 이용하고 싶을 경우에는 spring.config.location
에 파일명이나 경로를 설정해야 합니다.
spring.config.location
은 구성파일 내의 프로퍼티들을 읽어들이기 전에 설정되어야하는 속성으로, 프로퍼티 내에 설정하는 것이 아닌 환경 변수로 설정해야 하는 값입니다.
Java에서 환경변수를 설정하는 방법을 알아봅시다
3.1. OS의 환경변수에 설정
OS의 환경변수에 spring.config.location
변수를 추가할 경우, java 앱 실행시 자동으로 환경변수를 인식합니다.
환경 변수 설정하는 방법을 잘 모르겠다면 환경변수 Java에서 이용하기 게시글을 참고해주세요.
환경 변수를 추가한 후 앱을 실행해 봅시다.
OS 환경변수로 프로퍼티를 설정했기 때문에 커맨드 인자값을 설정할 필요가 없습니다.
java -jar demo.jar
3.2. command-line argument로 설정
웹 애플리케이션 시작시 커맨드 라인 인자값으로 프로퍼티값을 설정할 수 있습니다.
터미널에서 spring boot 웹 애플리케이션을 실행할 때엔 --spring.config.location
을 인자로 설정하면 됩니다.
java -jar --spring.config.location=classpath:/application.yml,classpath:/demo.yml demo.jar
java -jar demo.jar --spring.config.location="file:///var/lib/jenkins/deploys/demo/conf/application.yml,/var/lib/jenkins/deploys/demo/conf/demo.yml"
만일, Eclipse IDE에서 웹 애플리케이션을 실행하고 싶다면 웹 애플리케이션의 Config를 열어 Arguments 탭에 인자값을 설정하면 됩니다.
3.3. Java 코드에 설정
DemoApplication이 시작되기 전에 코드상에서 시스템 변수를 추가할 수도 있습니다.
@SpringBootApplication public class DemoApplication { static { System.setProperty("spring.config.location", "classpath:/application.yml,classpath:/demo.yml"); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
++ 주의 ★★
참고로, maven test 기능을 이용할 경우에는, @SpringBootTest 에도 프로퍼티 설정을 추가해줘야합니다.
추가하지 않을 경우에는 메이븐 테스트 시 demo.yml
프로퍼티를 읽어들이지 못하여 아래와 같은 BUILD FAILURE이 발생됩니다.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'openAPI' defined in class path resource [me/jiniworld/demo/configs/OpenApiConfig.class]: Unexpected exception during bean creation; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'demo.version' in value "${demo.version}"
[INFO] Results: [INFO] [ERROR] Errors: [ERROR] DemoApplicationTests.contextLoads » IllegalState Failed to load ApplicationCon... [INFO] [ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 57.176 s [INFO] Finished at: 2020-08-15T20:39:54+09:00 [INFO] ------------------------------------------------------------------------
@RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { static { System.setProperty("spring.config.location", "classpath:/application.yml,classpath:/demo.yml"); } ... }
@SpringBootApplication 애너테이션이 설정되어있었던 DemoApplication 클래스와 마찬가지로 static 블럭에 위와 같은 시스템 변수를 추가해주면 됩니다.
3.2. 테스트
웹애플리케이션을 시작한 후 추가했던 api를 조회해봅니다.
demo.yml에 설정한 값이 잘 읽어지는 것을 확인 할 수 있습니다.
4. Spring Boot 2.4 이상 버전 2021.11.25 업데이트
Spring Boot 2.4 버전부터는 config 파일을 import하는 구문을 지원합니다. [참고]
spring: application: name: demo profiles: active: local config: import: classpath:/demo.yml
기본 프로퍼티인 classpath:/application.yml
을 제외한 다른 config 파일을 포함시키고 싶다면 위와같이 spring.config.import
에 포함시킬 프로퍼티 파일을 설정하면 됩니다.
여러개를 설정해야한다면
,
로 구분지어 여러개를 설정하면 됩니다.
5. 결론
spring Boot 2.4 미만버전이라면
OS환경별로 다른 구성파일을 설정하고 싶다면 3.1 방법을 사용하면 되고,
웹 애플리케이션 시작시 커맨드 라인 인자값을 각기 다르게 설정하여 다양한 테스트를 하고 싶다면 3.2 방법을 사용하면 됩니다.
환경에 상관없이 고정적으로 여러개의 구성파일을 설정하고 싶다면 3.3 방법을 사용하는것을 추천합니다.(웹 애플리케이션 시작시 변수를 설정할 번거로움이 없기 때문에)
spring Boot 2.4 이상버전이라면
application.yml 의 spring.config.import
에 추가할 프로퍼티를 설정하면 됩니다.
프로퍼티에 설정하지 않은 필드는 null로 설정되며, 프로퍼티가 중복적으로 정의되어있을 경우 나중에 정의된 프로퍼티로 override 됩니다.
application.yml과 demo.yml에 동일한 프로퍼티가 정의되어있을 경우
spring.config.location
설정 시 나중에 입력된 demo.yml에 입력된 프로퍼티값으로 override됩니다.
++
- Externalized Configuration
- spring.config.location 환경 변수 설정하기
- Spring boot에서 여러개의 yml파일 적용하기
- application.yml 분리하기
Reference
'Spring > Basic' 카테고리의 다른 글
[Spring Boot] REST API의 request header, body logging 설정하기 (0) | 2020.10.20 |
---|---|
[Thymeleaf] inline javascript에서 유니코드로 표기된 한글문자 한글로 표기 (0) | 2020.06.18 |
[Spring Boot] JavaConfig로 Datasource 설정하기 (0) | 2020.04.05 |
[Spring Security] postman에서 csrf token 이용하기 (0) | 2020.03.23 |
[JPA] @MappedSuperclass로 중복 컬럼 상속화 (0) | 2019.12.30 |