Spring, Apache, Java

외부설정 사용

cwchoiit 2024. 6. 16. 17:44
728x90
반응형
SMALL

지금까지 외부 설정을 어떻게 하는지 자세히 알아봤으니 이제 그렇게 설정한 값들을 사용해보는 방법도 익혀보자.

크게 세가지 방식이 존재한다.

  • Environment
  • @Value - 값 주입
  • @ConfigurationProperties - 타입 안전한 설정 속성

Environment는 이미 한번 다뤄본 적이 있다. 그래도 한번 더 사용해서 어떤점이 불편해서 새로운 방식이 나온건지도 알아보자.

 

외부설정 사용 - Environment

우선, 가상의 DataSource를 하나 만들고, 여기에 필요한 속성들을 외부 설정값으로 채운 다음 스프링 빈으로 등록할 것이다.

 

application.yml

my:
  datasource:
    url: local.db.com
    username: username
    password: password
    etc:
      max-connection: 1
      timeout: 3500ms
      options: CACHE,ADMIN

 

MyDataSource

package hello.datasource;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.util.List;

@Slf4j
public class MyDataSource {
    private String url;
    private String username;
    private String password;
    private int maxConnection;
    private Duration timeout;
    private List<String> options;

    public MyDataSource(String url,
                        String username,
                        String password,
                        int maxConnection,
                        Duration timeout,
                        List<String> options) {
        this.url = url;
        this.username = username;
        this.password = password;
        this.maxConnection = maxConnection;
        this.timeout = timeout;
        this.options = options;
    }

    @PostConstruct
    public void init() {
        log.info("url: {}", url);
        log.info("username: {}", username);
        log.info("password: {}", password);
        log.info("maxConnection: {}", maxConnection);
        log.info("timeout: {}", timeout);
        log.info("options: {}", options);
    }
}

 

MyDataSourceEnvConfig

package hello.config;

import hello.datasource.MyDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.time.Duration;
import java.util.List;

@Slf4j
@Configuration
public class MyDataSourceEnvConfig {

    private final Environment environment;

    public MyDataSourceEnvConfig(Environment environment) {
        this.environment = environment;
    }

    @Bean
    public MyDataSource myDataSource() {
        String url = environment.getProperty("my.datasource.url");
        String username = environment.getProperty("my.datasource.username");
        String password = environment.getProperty("my.datasource.password");
        Integer maxConnection = environment.getProperty("my.datasource.etc.max-connection", Integer.class);
        Duration duration = environment.getProperty("my.datasource.etc.timeout", Duration.class);
        List<String> options = environment.getProperty("my.datasource.etc.options", List.class);

        return new MyDataSource(url, username, password, maxConnection, duration, options);
    }
}

 

MyDataSourceEnvConfig 여기에서 MyDataSource를 빈으로 등록한 다음 필요한 값들을 Environment를 통해 외부 설정으로부터 가져온다. 이 Environment는 어떤 외부 설정이던 상관없이 가져올 수 있게 스프링이 제공해주는 아주 좋은 추상화된 객체이므로 위 코드처럼 값들을 가져올 수 있다.

 

한번 서버를 실행해보면 결과는 다음과 같다.

보이는 것처럼 @PostConstruct에 의해 호출된 데이터값들이 잘 보여진다. 

근데, 이 방식은 어떤 단점이 있는가하면, 이 Environment를 직접 주입받는 것 자체에 있다. 주입을 직접 받는것도 불편하지만 받은 객체를 통해 계속해서 .getProperty()를 호출해서 꺼내와야만 한다. 이것을 반복하는 게 단점이다. 스프링은 @Value를 통해서 외부 설정값을 주입 받는 더욱 편리한 기능을 제공한다.

 

@Value

이 방법은 스프링이 외부 설정값을 편리하게 주입받게 해주는 방법이다. (사실 이 방법도 내부적으로는 Environment를 사용한다)

 

MyDataSourceValueConfig

package hello.config;

import hello.datasource.MyDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;
import java.util.List;

@Slf4j
@Configuration
public class MyDataSourceValueConfig {

    @Value("${my.datasource.url}")
    private String url;
    @Value("${my.datasource.username}")
    private String username;
    @Value("${my.datasource.password}")
    private String password;
    @Value("${my.datasource.etc.max-connection}")
    private int maxConnection;
    @Value("${my.datasource.etc.timeout}")
    private Duration timeout;
    @Value("${my.datasource.etc.options}")
    private List<String> options;

    @Bean
    public MyDataSource myDataSource1() {
        return new MyDataSource(url, username, password, maxConnection, timeout, options);
    }
}

이렇게 스프링이 제공하는 @Value를 사용해서 외부 설정값을 "${}" 이 안에 가져올 수 있다.

근데, 이 방법은 다른 방식도 있다. 파라미터로 받는 방법도 있는데 다음과 같이 사용하면 된다.

 

MyDataSourceValueConfig

package hello.config;

import hello.datasource.MyDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;
import java.util.List;

@Slf4j
@Configuration
public class MyDataSourceValueConfig {

    @Bean
    public MyDataSource myDataSource2(@Value("${my.datasource.url}") String url,
                                      @Value("${my.datasource.username}") String username,
                                      @Value("${my.datasource.password}") String password,
                                      @Value("${my.datasource.etc.max-connection}") int maxConnection,
                                      @Value("${my.datasource.etc.timeout}") Duration timeout,
                                      @Value("${my.datasource.etc.options}") List<String> options) {
        return new MyDataSource(url, username, password, maxConnection, timeout, options);
    }
}

이렇게해도 가져올 수 있다. 그리고 이 방법은 외부 설정에서 값을 찾지 못하면 기본값으로 대체할 수 있는 기능도 제공하는데 이는 ":"로 기본값을 추가적으로 작성하면 된다.

@Value("${my.datasource.etc.max-connection:2}")
private int maxConnection;

이렇게 :2 라고 해두면 없는 경우 기본값을 2로 받아오겠다는 의미가 된다.

 

그래서 이렇게 간단하게 가져올 수는 있다만 이 방법 역시 하나하나 외부 설정 정보의 키 값을 입력받고 주입 받아와야 하는 부분이 번거롭다. 그리고 설정 데이터를 보면 하나하나 분리되어 있는 게 아니라 정보의 묶음으로 되어 있다. my.datasource.xxx 이렇게 말이다.

그 말은 이 부분을 객체로 변환해서 사용할 수 있다면 더 편리하고 더 좋을 것이다. 그 방법을 알아보자.

 

외부 설정 사용 - @ConfigurationProperties

이번에는 외부 설정 값을 객체로 가져올 수 있는 방법에 대해 알아보자.

우선, 객체로 가져오려면 객체가 필요하다.

 

MyDataSourcePropertiesV1

package hello.datasource;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

@Data
@ConfigurationProperties("my.datasource")
public class MyDataSourcePropertiesV1 {

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

    @Data
    public static class Etc {
        private int maxConnection;
        private Duration timeout;
        private List<String> options = new ArrayList<>();
    }
}

 

이 객체를 보면, @ConfigurationProperties("my.datasource") 애노테이션이 있다. 이 애노테이션을 사용하면, .yml 파일이나 .properties 파일에 값을 등록한 `my.datasource`키에 대한 값을 객체로 변환해서 읽어오게된다.

 

그리고 그 중에 url, username, password는 바로 접근할 수 있지만, max-connection, timeout, optionsetc라는 키 하위에 존재한다. 다음 application.yml 파일을 비교해서 봐보자.

my:
  datasource:
    url: local.db.com
    username: local_user
    password: local_pw
    etc:
      max-connection: 1
      timeout: 60s
      options: LOCAL, CACHE

그래서, 내부 클래스로 이 값들 또한 객체로 받아준다. 이렇게 설정하고 나면 Configuration 클래스가 필요하다.

 

MyDataSourcePropertiesConfigV1

package hello.config;

import hello.datasource.MyDataSource;
import hello.datasource.MyDataSourcePropertiesV1;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

@Slf4j
@EnableConfigurationProperties(MyDataSourcePropertiesV1.class)
public class MyDataSourcePropertiesConfigV1 {

    private final MyDataSourcePropertiesV1 properties;

    public MyDataSourcePropertiesConfigV1(MyDataSourcePropertiesV1 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());
    }
}

이 파일에서 중요한 부분은 @EnableConfigurationProperties(MyDataSourcePropertiesV1.class) 애노테이션이다.

이 애노테이션을 달아서, MyDataSourcePropertiesV1 클래스를 통해 외부 설정값들을 클래스 형태의 빈으로 등록한다.

빈으로 등록했으니, 주입하면 된다. 주입하면 MyDataSource를 빈으로 등록하기 위한 값을 사용하면 된다. 

 

이제 @Import 애노테이션을 변경 후 실행해보자. 정상적으로 실행될 것이다.

ExternalReadApplication

package hello;

import hello.config.MyDataSourceEnvConfig;
import hello.config.MyDataSourcePropertiesConfigV1;
import hello.config.MyDataSourceValueConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.Import;

//@Import(MyDataSourceEnvConfig.class)
//@Import(MyDataSourceValueConfig.class)
@Import(MyDataSourcePropertiesConfigV1.class)
@SpringBootApplication(scanBasePackages = "hello.datasource")
public class ExternalReadApplication {

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

}

실행결과

2024-06-22T15:11:34.007+09:00  INFO 1827 --- [           main] hello.ExternalReadApplication            : Starting ExternalReadApplication using Java 17.0.9 with PID 1827 (/Users/choichiwon/Spring/external-read/out/production/classes started by choichiwon in /Users/choichiwon/Spring/external-read)
2024-06-22T15:11:34.008+09:00  INFO 1827 --- [           main] hello.ExternalReadApplication            : No active profile set, falling back to 1 default profile: "default"
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : url=local.db.com
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : username=local_user
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : password=local_pw
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : maxConnection=1
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : timeout=PT1M
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : options=[LOCAL, CACHE]
2024-06-22T15:11:34.217+09:00  INFO 1827 --- [           main] hello.ExternalReadApplication            : Started ExternalReadApplication in 0.387 seconds (process running for 0.578)

 

@PostConstruct 애노테이션으로 등록된 메서드가 실행되어 값이 잘 출력되는것을 볼 수 있다.

@ConfigurationProperties는 타입 안전 외부 설정이다. 즉, 아래와 같이 등록한 필드들의 타입을 보면

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

이 타입이 아닌 값이 외부 설정으로 부터 들어오면 에러를 뱉어낸다. 또한 계층 구조도 일치하는지 확인해주기 때문에 안전하고 재사용 가능한 객체 형태의 외부 설정값을 가져올 수 있다.

 

자, 객체 형태로 외부 설정을 가져와 빈으로 등록해서 여기저기 주입을 통해 사용할 수 있다는 것도 알게됐다. 근데 한가지 불편한 점이 있는데 아래 @ConfigurationProperties("my.datasource") 애노테이션을 붙였는데,

@Data
@ConfigurationProperties("my.datasource")
public class MyDataSourcePropertiesV1 {...}

 

여기서 또 @EnableConfigurationProperties(MyDataSourcePropertiesV1.class) 애노테이션을 붙여야 한다는 점이다.

@Slf4j
@EnableConfigurationProperties(MyDataSourcePropertiesV1.class)
public class MyDataSourcePropertiesConfigV1 {...}

 

그냥 한번만 애노테이션을 달면 좋겠는데, 귀찮게 두번 다 해줘야한다. 이 또한 해결 방법이 있다. 아래 애노테이션을 스프링 부트의 메인 클래스에 붙여주면 메인 클래스부터 하위 모든 패키지를 찾아서 @ConfigurationProperties 애노테이션을 등록한 클래스를 빈으로 알아서 등록해준다.

@ConfigurationPropertiesScan

 

확인해보자. 아래는 스프링 부트의 메인 클래스이다.

package hello;

import hello.config.MyDataSourceEnvConfig;
import hello.config.MyDataSourcePropertiesConfigV1;
import hello.config.MyDataSourceValueConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.Import;

//@Import(MyDataSourceEnvConfig.class)
//@Import(MyDataSourceValueConfig.class)
@Import(MyDataSourcePropertiesConfigV1.class)
@ConfigurationPropertiesScan
@SpringBootApplication(scanBasePackages = "hello.datasource")
public class ExternalReadApplication {

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

}

 

MyDataSourcePropertiesConfigV1

package hello.config;

import hello.datasource.MyDataSource;
import hello.datasource.MyDataSourcePropertiesV1;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

@Slf4j
// @EnableConfigurationProperties(MyDataSourcePropertiesV1.class)
public class MyDataSourcePropertiesConfigV1 {

    private final MyDataSourcePropertiesV1 properties;

    public MyDataSourcePropertiesConfigV1(MyDataSourcePropertiesV1 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());
    }
}

그리고 이제 @EnableConfigurationProperties(MyDataSourcePropertiesV1.class) 이 애노테이션을 주석처리했다.

실행해보면 결과는 동일하게 잘 동작한다.

 

실행결과

2024-06-22T15:11:34.007+09:00  INFO 1827 --- [           main] hello.ExternalReadApplication            : Starting ExternalReadApplication using Java 17.0.9 with PID 1827 (/Users/choichiwon/Spring/external-read/out/production/classes started by choichiwon in /Users/choichiwon/Spring/external-read)
2024-06-22T15:11:34.008+09:00  INFO 1827 --- [           main] hello.ExternalReadApplication            : No active profile set, falling back to 1 default profile: "default"
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : url=local.db.com
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : username=local_user
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : password=local_pw
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : maxConnection=1
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : timeout=PT1M
2024-06-22T15:11:34.179+09:00  INFO 1827 --- [           main] hello.datasource.MyDataSource            : options=[LOCAL, CACHE]
2024-06-22T15:11:34.217+09:00  INFO 1827 --- [           main] hello.ExternalReadApplication            : Started ExternalReadApplication in 0.387 seconds (process running for 0.578)

 

남은 문제

어느 정도 해결된 것 같지만, 한가지 정말 불편한 점이 있다. Lombok의 @Data 애노테이션을 사용했는데 이 애노테이션은 Setter를 자동으로 만들어주는 것이다. Setter는 되도록이면 없어야 한다. 적어도 난 그렇게한다. 세터로부터 파생되는 찾기 힘든 문제들이 너무 많기 때문에. 그래서 이 Setter 대신 생성자를 통해서 외부 설정 값을 넣는 방법을 알아보자. 

 

외부 설정 사용 - @ConfigurationProperties (생성자를 통해서)

위에 말한것처럼, 남은 문제가 있다. Setter를 남겨두고 싶지 않다. 그래서 생성자를 통해 외부 설정 값을 주입하는 방법이 있다.

아주 간단한데, 생성자만 만들면 끝이다.

 

MyDataSourcePropertiesV2

package hello.datasource;

import lombok.Data;
import lombok.Getter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

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

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

    public MyDataSourcePropertiesV2(String url, String username, String password, Etc etc) {
        this.url = url;
        this.username = username;
        this.password = password;
        this.etc = etc;
    }

    @Getter
    public static class Etc {
        private int maxConnection;
        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;
        }
    }
}

 

우선 V2를 만든다. 여기서는 @Data를 지우고, @Getter만 남겨두자. 그리고 이 클래스의 생성자를 만들면 된다. 위 코드처럼. 그럼 끝이다. 

 

실행결과

2024-06-29T15:22:08.257+09:00  INFO 71180 --- [           main] hello.datasource.MyDataSource            : url=local.db.com
2024-06-29T15:22:08.257+09:00  INFO 71180 --- [           main] hello.datasource.MyDataSource            : username=local_user
2024-06-29T15:22:08.257+09:00  INFO 71180 --- [           main] hello.datasource.MyDataSource            : password=local_pw
2024-06-29T15:22:08.257+09:00  INFO 71180 --- [           main] hello.datasource.MyDataSource            : maxConnection=1
2024-06-29T15:22:08.257+09:00  INFO 71180 --- [           main] hello.datasource.MyDataSource            : timeout=PT1M
2024-06-29T15:22:08.257+09:00  INFO 71180 --- [           main] hello.datasource.MyDataSource            : options=[DEFAULT]
2024-06-29T15:22:08.297+09:00  INFO 71180 --- [           main] hello.ExternalReadApplication            : Started ExternalReadApplication in 0.397 seconds (process running for 0.589)

Process finished with exit code 0

 

@PostConstruct 애노테이션으로부터 실행되는 메서드의 로그가 잘 출력됐고, 값도 잘 들어갔다. 그리고 V2에 보면 내부 클래스(Etc)의 생성자에 보면 @DefaultValue라는 애노테이션이 있다. 이건 외부 설정으로부터 해당 키가 없으면 그 값에 기본값을 넣어주는 방법이다. 그래서 해당 키가 있으면 그 값을 그대로 가져오고 없으면 저기에 선언한 기본값을 넣어준다.

 

스프링 3.0 이전에는 생성자에 @ConstructorBinding 애노테이션이 없으면 안됐다. 필수적으로 달아줘야 했던 애노테이션인데, 3.0 이후에는 생성자가 하나뿐이라면 생략 가능하다. 그래서 위 코드에서도 해당 애노테이션은 없다. 

 

남은 문제

남은 문제가 또 있다고?! 라고 생각하겠지만, 문제라기보단 더 많은 기능을 원한다. 이제는 생성자를 통해서 외부 설정값을 받아오고, 타입 안정성도 체크가 된다. 근데 검증을 하고 싶다. 예를 들면, max-connection이 최소 1보단 커야 이 값의 의미가 있다고 가정할때 0이 들어오면 아무런 의미없게 애플리케이션은 정상 동작을 하지 않을것이다. 그러나 타입 안정성에는 아무런 문제가 없기 때문에 어떤 에러로 인식시켜 주지 않는다. 내가 원하는건 만약 내가 실수로 0 또는 그보다 작은 수를 적었으면 바로 에러를 띄워 알려주길 원한다. 이게 가능할까?

 

외부 설정 사용 - @ConfigurationProperties (검증기 도입)

이제는 한 단계 더 나아가서 검증 기능까지 추가해서 더 안전한 외부 설정 주입을 사용해보자.

우선, 추가적인 의존성이 필요하다.

 

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-validation'

 

위와 같이 의존성 하나를 더 추가해주자. 그러면 다음과 같이 두 개가 보이면 된다.

 

참고로, 위 두개 중 패키지 이름에 jakarta.validation으로 시작하는 것은 자바 표준 검증기에서 지원하는 기능이다. org.hibernate.validator로 시작하는 것은 자바 표준 검증기에서 아직 표준화 된 기능은 아니고 하이버네이트 검증기라는 표준 검증기의 구현체에서 직접 제공하는 기능이다. 대부분 하이버네이트 검증기를 사용하므로 크게 문제될 건 없다.

 

그리고 외부 설정을 객체로 받을 클래스 하나를 새로 만든다.

 

MyDataSourcePropertiesV3

package hello.datasource;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import org.hibernate.validator.constraints.time.DurationMax;
import org.hibernate.validator.constraints.time.DurationMin;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.validation.annotation.Validated;

import java.time.Duration;
import java.util.List;

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

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

    public MyDataSourcePropertiesV3(String url, String username, String password, 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;
        }
    }
}

중요한 애노테이션은 클래스 레벨에 붙어있는 @Validated 이다. 이 애노테이션이 있어야 검증을 수행한다.

그리고, 각 필드별로 원하는 검증 단계를 적용할 수 있다. 위 코드로 예를 들면, @NotEmpty는 빈 값이면 안된다는 검증 단계이다.

그리고 @Min(1), @Max(999)는 말 그대로 최소값은 1, 최대값은 999란 소리다.

이렇게 검증기를 추가해서 더 안전한 외부 설정을 사용할 수 있다.

 

실행해보자. 현재 상태는 검증기도 다 만족하는 상태이기 때문에 다음과 같이 잘 실행된다.

2024-06-30T15:56:26.642+09:00  INFO 18860 --- [           main] hello.datasource.MyDataSource            : url: local.db.com
2024-06-30T15:56:26.642+09:00  INFO 18860 --- [           main] hello.datasource.MyDataSource            : username: username
2024-06-30T15:56:26.643+09:00  INFO 18860 --- [           main] hello.datasource.MyDataSource            : password: password
2024-06-30T15:56:26.643+09:00  INFO 18860 --- [           main] hello.datasource.MyDataSource            : maxConnection: 1
2024-06-30T15:56:26.643+09:00  INFO 18860 --- [           main] hello.datasource.MyDataSource            : timeout: PT3.5S
2024-06-30T15:56:26.643+09:00  INFO 18860 --- [           main] hello.datasource.MyDataSource            : options: [CACHE, ADMIN]
2024-06-30T15:56:26.790+09:00  INFO 18860 --- [           main] hello.ExternalReadApplication            : Started ExternalReadApplication in 0.744 seconds (process running for 1.084)

Process finished with exit code 0

 

그런데, 만약 내가 max-connection 값을 다음과 같이 0으로 바꾼다고 하면,

my:
  datasource:
    url: local.db.com
    username: username
    password: password
    etc:
      max-connection: 0 # 이 부분!
      timeout: 3500ms
      options: CACHE,ADMIN

 

실행 시 이러한 에러가 나타난다.

 

결론

이렇게 검증까지도 구현해 보았다. 외부 설정을 사용하고 읽어들이는 방법도 잘 사용해서 좋은 애플리케이션을 만들어보자!

 

728x90
반응형
LIST