티스토리 뷰
[SpringBoot] final 변수를 갖는 클래스에 프로퍼티(Properties) 설정 값 불러오기, 생성자 바인딩(Constructor Binding)
망나니개발자 2021. 9. 12. 10:00Spring 프레임워크로 개발을 하다 보면 프로퍼티(Properties)에 저장된 특정한 설정 값들을 불러와야 하는 경우가 있다. 많은 글 들에서 프로퍼티(Properties)를 불러오는 내용들을 설명하고 있는데, 이번에는 final 변수가 붙은 클래스에 설정 값을 불러오는 방법에 대해서 알아보고자 한다.
1. 수정자(Setter)로 클래스에 프로퍼티(Properties) 설정 값 불러오기
[ 설정값 및 프로퍼티(Properties) 클래스 ]
아주 쉬운 예시로 Properties에 다음과 같은 설정 파일들이 있다고 가정하자.
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=h2test
spring.datasource.password=h2test
그리고 이 datasource 관련 설정 값들을 다음과 같은 클래스로 한번에 불러오고 싶다고 하자.
@Getter
public class DataSourceProperties {
private String driverClassName;
private String url;
private String username;
private String password;
}
이때 설정 값들을 불러오기 위해서는 Setter를 이용해 수정자로 바인딩하거나 @Constructor Binding를 이용해 생성자로 바인딩을 할 수 있는데, 먼저 수정자로 바인딩해보도록 하자.
[ Setter로 바인딩하기 ]
우선 Spring으로 하여금 컨테이너가 시작될 때 DataSourceProperties 설정 클래스를 초기화하고 빈으로 생성하도록 등록을 해주어야 한다. 이를 위해서는 @EnableConfigurationProperties를 등록하고, 해당 클래스를 추가해주어야 한다.
일반적으로 SpringBoot의 메인 클래스에 @EnableConfigurationProperties 어노테이션을 다음과 같이 추가해준다.
@Configuration
@EnableConfigurationProperties({DataSourceProperties.class})
public class SpringBootApplication {
}
ConfigurationProperties는 기본적으로 자바빈 프로퍼티 방식으로 동작하기 때문에 Setter가 반드시 필요하다. 그러므로 우선 Properties 클래스에 Setterr가 필요하므로 추가해주록 하자. DatasourceProperties 클래스에 우리가 바인딩하고자 하는 값들의 prefix는 spring.datasource가 공통된다. 그러므로 Spring 컨테이너가 spring.datasource로 시작되는 properties값을 바인딩하도록 @ConfigurationProperties를 추가하고 prefix를 다음과 같이 설정해주어야 한다.
@Setter
@Getter
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {
private String driverClassName;
private String url;
private String username;
private String password;
}
그리고 실행을 해보면 다음과 같이 정상적으로 바인딩이 됨을 확인할 수 있다.
2. 생성자 바인딩(Constructor Binding)로 프로퍼티(Properties) 설정 값 불러오기
[ 생성자로 바인딩하기(@ConstructorBinding) ]
하지만 Setter가 추가된 DatasourceProperties는 그다지 좋은 방법이 아니다. 왜냐하면 Spring 컨테이너에 의해 싱글톤으로 관리되는 객체에 변경 가능성이 열려있기 때문이다. 그러므로 해당 클래스의 변수들을 final로 선언하고, 생성자로 바인딩하도록 수정하는 것이 좋다.
(불변 객체 및 final을 이용하는 이유에 대해서는 너무 중요하므로, 이해가 부족하다면 이 글에서 참고하도록 하자.)
변경 가능성을 닫기 위해서는 해당 변수들을 모두 final로 선언하고, 생성자를 추가해주면 된다. 그리고 생성자를 이용해 properties의 값을 바인딩하도록 @ConstructorBinding 어노테이션을 추가해주면 된다.
@Getter
@RequiredArgsConstructor
@ConfigurationProperties(prefix = "spring.datasource")
@ConstructorBinding
public class DataSourceProperties {
private final String driverClassName;
private final String url;
private final String username;
private final String password;
}
그리고 해당 프로퍼티의 값이 잘 불러와지는지 확인해보면 다음과 같이 정상적으로 불러와지는 것을 확인할 수 있다.
애플리케이션의 규모가 큰데, 변경 가능성이 열려 있어 변경 가능한 포인트가 많다면 나중에 유지보수가 어려워진다. 그러므로 불변 객체를 최대한 이용하도록 하고, 프로퍼티를 불러오는 경우에도 적용하도록 하자.
참고로 스프링부트 3.0부터는 1개의 생성자만 있는 경우에 기본적으로 생성자 방식으로 동작하도록 수정되었다고 한다. 따라서 생성자가 2개 이상 존재하지 않는 경우라면 @ConstructorBinding를 생략해주어도 된다.
하지만 프로퍼티 설정 클래스들이 상당히 많아진다면 일일이 등록하는게 번거로워질 수 있다. 그래서 Spring Boot 2.2부터는 @ConstructorBinding 어노테이션이 붙은 클래스들을 스캔하여 처리하는 기능을 제공하고 있다.
다음 포스팅에서는 이러한 작업을 진행하는 @ConfigurationPropertiesScan에 대해 알아보도록 하자.
관련 포스팅
- 설정 값 분리의 필요성과 @Value의 사용법 및 동작 과정
- @Value와 @ConfigurationProperties의 사용법 및 차이
- final 변수를 갖는 클래스에 프로퍼티(Properties) 설정 값 불러오기, 생성자 바인딩(Constructor Binding)
- @ConfigurationPropertiesScan을 이용한 설정 프로퍼티 클래스(@Configuration Properties)의 빈 등록