≣ 목차
@Value
application.properties 파일에 필요한 외부 설정을 추가한 후, @Value 애노테이션을 통해 해당 값들을 손쉽게 읽어올 수 있습니다. @Value는 내부적으로 Environment를 사용하여 설정 값을 가져옵니다. 이 애노테이션은 필드에 적용할 수 있을 뿐만 아니라, 메서드의 파라미터에도 사용할 수 있어 유연한 설정할 수 있습니다.
만약 특정 키를 찾지 못할 경우, 코드에서 기본값을 사용하고 싶다면, @Value 애노테이션의 값 뒤에 콜론(:)을 추가하고 기본값을 적어주면 됩니다.
@Value("${my.datasource.etc.max-connection:1}")
추가로, @Value를 사용할 때는 설정 값의 타입에 맞게 변환이 이루어지므로, 적절한 타입으로 변환될 수 있도록 주의해야 합니다.
파라미터 적용 예시
public MyDataSource myDataSource(
@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)
필드 적용 예시
@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;
@Value의 단점
@Value를 사용하여 소수의 외부 설정 정보를 키 값으로 입력받고 주입받는 것은 간편하지만, 많은 외부 설정 값을 처리하는 과정은 다소 번거로울 수 있습니다. 특히 설정 데이터를 살펴보면, 개별적으로 분리되어 있는 것이 아니라 정보의 묶음으로 제공되는 경우가 많습니다.
예를 들어, my.datasource와 같이 관련된 설정들이 함께 묶여 있는 경우가 많습니다. 이러한 설정들을 하나하나 @Value로 주입받는 것은 비효율적이며, 코드의 가독성을 떨어뜨릴 수 있습니다.
이런 경우에는 설정 데이터를 객체로 변환하여 사용하는 것이 더 편리하고 효율적입니다. 이렇게 하면 관련된 설정 값을 하나의 객체로 묶어 관리할 수 있어, 많은 외부 설정 값을 다룰 때 더욱 유용합니다.
@ConfigurationProperties
스프링 부트는 외부 설정 정보를 객체로 변환하는 기능을 제공하여 애플리케이션 설정을 보다 쉽게 관리할 수 있도록 합니다. 이 기능을 '타입 안전한 설정 속성'이라고 하며, @ConfigurationProperties를 사용하면 설정 값을 그룹화하여 체계적으로 관리할 수 있습니다.
이러한 방식은 복잡한 설정을 보다 명확하게 정리할 수 있게 해주며, 특정 설정 값이 예를 들어 int 자료형이어야 할 경우, 잘못된 타입(예: 문자열)이 들어오면 스프링이 오류 메시지를 반환하여 개발자가 문제를 쉽게 인지하고 수정할 수 있도록 도와줍니다.
Failed to bind properties under 'my.datasource.etc.max-connection' to int:
Property: my.datasource.etc.max-connection
Value: "test"
Origin: class path resource [application.properties] - 4:34
Reason: failed to convert java.lang.String to int (caused by java.lang.NumberFormatException: For input string: "test")
또한, @ConfigurationProperties를 사용할 때는 getter와 setter 메서드가 필요합니다. 이는 스프링이 해당 프로퍼티 값을 자동으로 바인딩하고, 스프링 빈으로 등록하여 필요한 곳에서 쉽게 사용할 수 있도록 하기 위함입니다.
@ConfigurationProperties 데이터 검증
@ConfigurationProperties를 사용하면 외부 설정에서 가져온 값의 타입을 안전하게 관리할 수 있습니다. 그러나 숫자의 범위나 문자열의 길이와 같은 추가적인 검증은 기본적으로 제공되지 않기 때문에 개발자가 직접 검증 로직을 작성해야 할 필요가 있습니다. 이를 해결하기 위해 자바에서는 자바 빈 검증기(Java Bean Validation)라는 강력한 표준 검증기를 제공합니다.
외부 설정 프로퍼티(객체)
@Getter
@Setter
@ConfigurationProperties("my.datasource")
@Validated
public class MyDataSourceProperties {
@NotEmpty
private String url;
@NotEmpty
private String username;
@NotEmpty
private String password;
private Etc etc;
@Getter
@Setter
public static class Etc {
@Min(1)
@Max(99)
private int maxConnection;
@DurationMin(seconds =1)
@DurationMax(seconds =60)
private Duration timeout;
private List<String> options = new ArrayList<>();
}
}
@Validated를 클래스에 추가하면, 스프링이 해당 클래스의 필드에 적용된 검증 애노테이션(예: @NotEmpty, @Min, @Max, @DurationMin, @DurationMax)을 자동으로 검사합니다. 이를 통해 외부 설정 값이 유효한지 확인할 수 있습니다.
설정
@Slf4j
@EnableConfigurationProperties(MyDataSourceProperties.class)
public class MyDataSourceConfig {
private final MyDataSourceProperties properties;
public MyDataSourceConfig(MyDataSourceProperties properties) {
this.properties = properties;
}
@Bean
public MyDataSource myDataSource() {
return new MyDataSource(
properties.getUrl(),
properties.getUsername(),
properties.getPassword(),
properties.getEtc().getMaxConnection(),
properties.getEtc().getTimeout(),
properties.getEtc().getOptions());
}
}
@EnableConfigurationProperties(MyDataSourceProperties.class)는 스프링에서 특정 프로퍼티 클래스를 활성화하여 해당 클래스의 프로퍼티를 애플리케이션의 설정 파일(예: application.properties 또는 application.yml)에서 읽어올 수 있도록 하는 애노테이션입니다.
추가적으로 @ConfigurationPropertiesScan과 @EnableConfigurationProperties는 스프링에서 설정 프로퍼티를 관리하는 애노테이션으로, @EnableConfigurationProperties는 특정 클래스에 대해 @ConfigurationProperties를 직접 등록할 때 사용되며, 예를 들어 @EnableConfigurationProperties(MyDataSourceProperties.class)와 같이 특정 프로퍼티 클래스를 명시적으로 등록합니다. 반면, @ConfigurationPropertiesScan은 특정 범위 내의 모든 @ConfigurationProperties 클래스를 자동으로 등록할 때 사용되어 여러 프로퍼티 클래스를 한 번에 스캔하고 등록할 수 있습니다. 따라서 개별적으로 프로퍼티 클래스를 등록하고 싶다면 @EnableConfigurationProperties를, 여러 클래스를 자동으로 등록하고 싶다면 @ConfigurationPropertiesScan을 사용하는 것이 좋습니다.
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {}
@ConfigurationProperties의 문제: Setter 제거의 필요성
MyDataSourceProperties는 스프링 빈으로 등록되며, 외부 설정값을 사용하여 초기화됩니다. 그러나 Setter 메서드가 존재하면 실수로 값이 변경될 가능성이 있습니다. 이러한 변경은 예기치 않은 버그를 초래할 수 있습니다.
따라서 Setter를 제거하고 생성자를 통해 값을 설정하는 방식으로 변경하면, 중간에 데이터가 수정되는 것을 방지할 수 있습니다. 생성자를 사용하면 객체가 생성될 때 필요한 모든 값을 한 번에 설정할 수 있어, 이후에 값이 변경되지 않도록 보장할 수 있습니다. 비록 대부분의 개발자가 MyDataSourceProperties의 값은 변경해서는 안 된다는 것을 인지하고 있지만, 어떤 개발자가 자신의 문제를 해결하기 위해 Setter를 사용하게 되면 애플리케이션 전체에 심각한 영향을 미칠 수 있습니다.
@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(99)
private int maxConnection;
@DurationMin(seconds =1)
@DurationMax(seconds =60)
private Duration timeout;
private List<String> options = new ArrayList<>();
public Etc(int maxConnection, Duration timeout, List<String> options) {
this.maxConnection = maxConnection;
this.timeout = timeout;
this.options = options;
}
}
}
'Devops' 카테고리의 다른 글
[부하테스트] 부하 테스트 서버 설정 시 주의점 (0) | 2025.03.20 |
---|---|
[부하 테스트] 기초 용어 정리 + 추가 Tip 정리 (0) | 2025.03.20 |
[Devops] AWS EC2 인스턴스 유형 및 선택 방법 (0) | 2024.05.08 |
[Devops] AWS EC2 기본 개념 및 구성 (0) | 2024.05.08 |
[Devops] Public IP, Private IP 용어 정리 (0) | 2024.05.08 |