-
[06] 외부 설정 file (Property)Spring/Spring boot 2020. 6. 1. 11:52반응형
[외부 설정의 file 종류와 우선순위]
외부 설정 file은 application에서 사용하는 여러 가지 properties를 담아놓은 file로 application 내부 또는 외부에 위치할 수 있습니다. 외부 설정 file은 다음과 같은 것들이 있습니다.
- properties (application.properties)
- YAML
- 환경변수 (environment variable)
- Command line arguments
Properties는 여러 군데 산재할 수 있으며 각각의 다른 외부 설정에 동일한 property key가 존재할 경우 우선순위에 따라 property에 해당되는 value를 선택하게 됩니다. property의 우선순위는 다음과 같습니다.
- home directory에 있는 spring-boot-dev-tools.properties file
- test code에 붙이는 @TestPropertySource에 해당하는 properties
- @SpringBootTest annotaion의 properties attribute
- command line arguments
- SPRING_APPLICATION_JSON (환경변수 또는 system property)에 들어있는 properties
- ServletConfig parameter
- ServletContext parameter
- java:comp/env JNDI attribute
- System.getProperties() Java system properties
- OS environment variable
application.properties file 위치에 따라서도 우선순위가 달라지는데 그 순서는 다음과 같습니다.
- file:./config/
- file:./
- classpath:/config/
- classpath:/
[Property의 접근]
여러가지 방법으로 property에 설정한 value에 접근할 수 있습니다.
- Environment type bean의 getProperty() method를 통해 접근 (참고)
- @Value annotation에 SpringEL을 사용하여 접근 (참고)
- @ConfigurationProperties("{PropertyName}") annotation을 적용한 class type의 bean을 통해 접근
1, 2에 해당하는 접근 방법은 링크를 참고해주시고 여기서는 3번에 해당하는 예제만 살펴보도록 합니다.
bean을 통해 접근하기 위해 bean을 등록해야 하는데 property 접근 class type의 bean을 등록하는 방법은 3가지가 있습니다.
- main class에 @EnableConfigurationProperties({property 접근 class}) 적용
- property 접근 class에 @Component 적용
- third party configuration에 정의된 class를 사용할 경우 @Bean을 사용하여 적용
application.properties file의 내용은 다음과 같이 작성합니다.
test.name=dave test.age=${random.int(0,120)} test.company=SarangCompany
위의 application.properties file에 정의된 properties를 읽어올 class를 다음과 같이 선언합니다.
//@Primary // ① @Component // ② @ConfigurationProperties("test") // ③ public class AccessProperties { // ④ String name; int age; String company; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } }
① main class에서 @EnableConfigurationProperties annotation을 사용하여 property를 접근하기 위한 class를 지정하는 경우 @EnableConfigurationProperties에 의해 bean이 생성되며 현재 class에 지정된 @Component에 의해서도 bean으로 등록되어 동일 type의 bean이 두 개가 생성되므로 @primary annotation을 사용하던가 현재 class의 @Component를 제거해줍니다.
② property에 접근하기 위한 class의 instance는 bean으로 등록되어야 하기 때문에 class에 @Component를 붙여줍니다.
③ 이 class type의 bean이 어떤 property key(또는 key group)에 대해 접근할지 지정합니다.
④ application.properties file에서 접근하고자 하는 property들을 member변수로 선언합니다. 변수명은 properties file의 property와 동일하게 선언해줍니다. 변수 type의 경우 property에 지정된 value를 참고하여 적당한 type으로 선언해주면 됩니다. 또한 property의 value는 모두 String 형태이지만 그 값에 따라 Spring boot에서 자동으로 type을 변환하여 class의 member변수에 대입시켜 줍니다. 예를 들어 property의 age는 문자열 형태의 숫자이지만 member변수로 대입될 때는 숫자로 변환되어 들어갑니다.
bean을 통해 property에 접근이 가능한지 확인하기 위해 Runner class를 다음과 같이 생성합니다.
@Component public class AppRunner implements ApplicationRunner { @Autowired AccessProperties properties; // ① public void run(ApplicationArguments args) throws Exception { // ② System.out.println(properties.getName()); System.out.println(properties.getAge()); System.out.println(properties.getCompany()); } }
① property에 접근하기 위한 bean을 주입받습니다.
② 주입받은 bean의 getter를 사용하여 property value를 접근합니다.
main class에서 @EnableConfigurationProperties({property 접근 class})를 사용하여 property 접근 class type의 bean을 생성할 수 있습니다. 위에서도 설명했지만 이럴 경우 property 접근 class에 붙어있는 @Component계열 annotation을 모두 제거하거나 @Primary annotation을 붙여야 합니다. main class 코드는 다음과 같습니다.
@SpringBootApplication @EnableConfigurationProperties(AccessProperties.class) // ① public class Application { @Autowired AccessProperties properties; public static void main(String[] args) { SpringApplication app = new SpringApplication(Application.class); app.setWebApplicationType(WebApplicationType.NONE); app.run(args); } }
① property에 접근할 수 있는 class들을 지정하여 bean으로 등록하고 property 접근 class에 설정된 @ConfigurationProperties annotation을 적용해 줍니다. @EnableConfiguratioinProperties는 자동으로 적용되므로 생략할 수 있고 이런 경우 property 접근 class type의 bean이 생성까지는 되지 않으므로 각각의 property 접근 class에 @Component annotaion을 붙여 bean으로 등록해야 합니다.
property 접근 class type의 bean을 통한 property binding은 융통성 있게 진행됩니다. 즉, key에 "_" 또는 "-"와 같은 문자가 들어가 있어도 binding을 진행해 줍니다.
property binding 시 spring framework에서 제공하는 ConversionService를 통해 문자열 형태의 property value를 원하는 member변수 type으로 자동 변환합니다. ConversionService를 통한 자동변환 중 시간에 해당하는 value를 받아올 때 유용하게 사용할 수 있는 것이 있습니다. property 접근 class의 member변수 중 property에 정의된 시간정보 key에 해당하는 변수에 다음과 같이 @DurationUnit() annotaion을 붙여주는 것으로 자동변환을 사용할 수 있습니다.
@Component @Configuration("test") public class AccessProperties { @DurationUnit(ChronoUnit.SECONDS) private Duration timeOut; public Duration getTimeOut() { return timeOut; } public void setTimeOut(Duration timeOut) { this.timeOut = timeOut; } }
application.properties file에 test.timeOut key를 만들고 다음과 같이 값을 지정합니다.
test.timeOut=50
위의 class type의 bean을 통해 timeOut property 값을 출력하면 다음과 같이 Duration type으로 자동 변환됨을 볼 수 있습니다.
@DurationUnit을 사용하지 않더라도 property value가 숫자+s 형태 (예를 들어 50s)이면 자동 변환이 이뤄져 위와 동일한 결과를 보여주게 됩니다.
[Property value의 검증]
Property value를 검증하기 위해 property 접근 class에 @Validated annotation을 붙여줍니다. JSR303 validation API (hibernate validation 구현체를 사용)를 사용하여 @NotEmpty, @NotNull 등과 같이 validation checking이 가능합니다.
[application.properties file 사용 시 주의 점]
project를 진행할 때 견고한 software를 제작하기 위해 test code를 작성하게 됩니다. 다만 build 시 main package와 test package는 각각의 application.properties file을 가지고 packaging 하게 되고 packaging 순서는 main -> test 순입니다. 따라서 두 package의 application.properties 내용이 다르다면 다른 실행 결과를 보여줄 수도 있습니다. 이를 방지하기 위해 test의 resource에 있는 application.properties file을 삭제하면 test build 시 main에 있는 application.properties file을 그대로 가져다 쓰게 됩니다.
[Radom value 설정과 place holder]
property의 value에 random한 값을 넣어줄 수 있습니다.
- test.number=${random.*}
property의 value는 다른 property의 value를 구성하는 요소 즉, place holder로 사용될 수 있습니다.
- test.familyName=kim
- test.fullName=dave ${test.familyName}
'Spring > Spring boot' 카테고리의 다른 글
[08] Spring boot logging (0) 2020.06.05 [07] Profile (0) 2020.06.03 [05] Spring Application (0) 2020.05.28 [04] 독립으로 실행가능한 JAR file (0) 2020.05.26 [03] 내장 Web Application Server (0) 2020.05.20