스프링 부트(핵심 원리와 활용)

Ch06. 외부설정과 프로필(2) - 외부 설정 사용(@ConfigurationProperties 검증)

webmaster 2023. 3. 18. 17:07
728x90

@ConfigurationProperties를 통해서 숫자가 들어가야 하는 부분에 문자가 입력되는 문제와 같은 타입이 맞지 않는 데이터를 입력하는 문제는 예방할 수 있다. 그런데 문제는 숫자의 범위라던가, 문자의 길이 같은 부분은 검증이 어렵다.
예를 들어서 최대 커넥션 숫자는 최소 1, 최대 999라는 범위를 가져야 한다면 어떻게 검증할 수 있을까? 이메일을 외부 설정에 입력했는데, 만약 이메일 형식에 맞지 않는다면 어떻게 검증할 수 있을까?
개발자가 직접 하나하나 검증 코드를 작성해도 되지만, 자바에는 자바 빈 검증기(java bean validation)이라는 훌륭한 표준 검증기가 제공된다.
@ConfigurationProperties 은 자바 객체이기 때문에 스프링이 자바 빈 검증기를 사용할 수 있도록 지원한다.

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    implementation 'org.springframework.boot:spring-boot-starter-validation' //추가

    //test lombok 사용
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
}

MyDataSourcePropertiesV3

@Getter
@Validated
@ConfigurationProperties("my.datasource")
public class MyDataSourcePropertiesV3 {

  @NotEmpty
  private String url;
  @NotEmpty
  private String username;
  @NotEmpty
  private String password;
  private Etc etc;

  //@ConstructorBinding //생성자가 하나일 경우에는 생략 가능하다
  public MyDataSourcePropertiesV3(String url, String username, String password,
      @DefaultValue Etc etc) {
    this.url = url;
    this.username = username;
    this.password = password;
    this.etc = etc;
  }

  @Getter
  public static class Etc {

    @Min(1)
    @Max(999)
    private int maxConnection;

    @DurationMin(seconds = 1)
    @DurationMax(seconds = 60)
    private Duration timeout;

    private List<String> options;

    public Etc(int maxConnection, Duration timeout, @DefaultValue("DEFAULT") List<String> options) {
      this.maxConnection = maxConnection;
      this.timeout = timeout;
      this.options = options;
    }
  }

}
  • @NotEmpty url , username , password 는 항상 값이 있어야 한다. 필수 값이 된다.
  • @Min(1) @Max(999) maxConnection : 최소 1 , 최대 999 의 값을 허용한다.
  • @DurationMin(seconds = 1) @DurationMax(seconds = 60) : 최소 1, 최대 60초를 허용한다
  • jakarta.validation.constraints.Max
    • 패키지 이름에 jakarta.validation 으로 시작하는 것은 자바 표준 검증기에서 지원하는 기능이다.
  • org.hibernate.validator.constraints.time.DurationMax
    • 패키지 이름에 org.hibernate.validator 로 시작하는 것은 자바 표준 검증기에서 아직 표준화 된 기능은 아니고, 하이버네이트 검증기라는 표준 검증기의 구현체에서 직접 제공하는 기능이다. 대부분 하이버네이트 검증기를 사용하므로 이 부분이 크게 문제가 되지는 않는다.

MyDataSourceConfigV3

@Slf4j
@EnableConfigurationProperties(MyDataSourcePropertiesV3.class)
public class MyDataSourceConfigV3 {

  private final MyDataSourcePropertiesV3 properties;

  public MyDataSourceConfigV3(MyDataSourcePropertiesV3 properties) {
    this.properties = properties;
  }

  @Bean
  public MyDataSource dataSource() {
    return new MyDataSource(properties.getUrl(),
        properties.getUsername(),
        properties.getPassword(),
        properties.getEtc().getMaxConnection(),
        properties.getEtc().getTimeout(),
        properties.getEtc().getOptions());
  }
}
  • MyDataSourceConfigV3 은 기존 코드와 크게 다르지 않다.

ExternalReadApplication - 수정

@Import(MyDataSourceConfigV3.class)
@SpringBootApplication(scanBasePackages = "hello.datasource")
@ConfigurationPropertiesScan({"hello"}) //해당 어노테이션이 있으면 ComponentScan 처럼 빈을 등록 안해도 된다.
public class ExternalReadApplication {

    public static void main(String[] args) {
        SpringApplication.run(ExternalReadApplication.class, args);
    }

}
  • @Import(MyDataSourceConfigV3.class) 를 추가 한다.

정리

ConfigurationProperties 덕분에 타입 안전하고, 또 매우 편리하게 외부 설정을 사용할 수 있다. 그리고 검증기 덕분에 쉽고 편리하게 설정 정보를 검증할 수 있다.
가장 좋은 예외는 컴파일 예외, 그리고 애플리케이션 로딩 시점에 발생하는 예외이다. 가장 나쁜 예외는 고객 서비스 중에 발생하는 런타임 예외이다.

ConfigurationProperties 장점

  • 외부 설정을 객체로 편리하게 변환해서 사용할 수 있다.
  • 외부 설정의 계층을 객체로 편리하게 표현할 수 있다.
  • 외부 설정을 타입 안전하게 사용할 수 있다.
  • 검증기를 적용할 수 있다.
728x90