SpringBoot 외부 프로퍼티 적용 @Value, @ConfigurationProperties

Donghyun Kim·2023년 7월 26일
0

SpringBoot 프로젝트에서는 application.yml 파일을 사용하여 외부 프로퍼티 값을 관리할 수 있다.
이 프로퍼티 값을 Java 코드내에서 바인딩하여 사용할 수 있게 도와주는 Spring 어노테이션인 @Value @ConfigurationProperties 어노테이션에 대해 알아보자

apllication.yml

테스트를 위해 다음과 같은 프로퍼티를 작성한다.

app:
  test:
    name: Hello
    list: a,b,c

@Value

프로퍼티의 key를 통해 값을 Java 변수에 바인딩할 수 있다.

Java Code

@Getter
@Setter
public class PropertiesTest {

	@Value("${app.test.name}")
	private String testName;

	@Value("${app.test.list}")
	private List<String> testList;
}

위 방식은 간단하게 프로퍼티의 키를 바인딩할 수 있지만 몇 가지 문제가 있다.

  • 해당 프로퍼티가 없으면 무조건 예외가 발생한다.
  • 타입이 불안정하다.
    • 프로퍼티가 true라면 Boolean, String 모두 캐스팅이 된다.
    • 이를 막으려면 spEL을 사용해야 한다. ex. @Value("{new Integer('${api.orders.pingFrequency}')}")
  • 프로퍼티가 많으면 코드가 지저분해진다.

@ConfigurationProperties

프로퍼티 키의 특정 prefix를 지정하여 Class에 선언된 변수명과 매핑하여 필드 값이 할당된 객체를 생성할 수 있다.

  • @Value가 가진 문제를 해소할 수 있다.

Java Code

@Getter
@Setter
@ConfigurationProperties("app.test")
public class PropertiesTest {

    private String name;
    private List<String> list;
    
}
  • @ConfigurationProperties의 value에 있는 경로의 프로퍼티를 자동으로 필드에 바인딩해준다. (참고로 kebab-case 프로퍼티명을 camelCase 필드로 바인딩)

  • 이 방법은 프로퍼티가 많더라도 깔끔하게 관리할 수 있다. 그리고 기본적으로 프로퍼티가 없어도 에러를 발생시키지 않는다.

    • @ConfigurationProperties의 ignoreUnknownProperties 속성을 false로 설정하면 강제로 오류를 발생하도록 설정할 수 있다.
    • @ConfigurationProperties(value = "app.directory", ignoreUnknownFields = true)

하지만 문제는 프로퍼티가 Setter를 통해 주입된다는 점이다. private set 메서드로도 주입이 가능하지만, 의미 없는 Setter를 만들게 되고, 그래서 final 키워드를 사용할 수 없게 되고 도메인 의미가 불분명해진다.

@ContsructorBinding

Spring Boot 2.3 버전 이상부터는 생성자 주입방식으로 불변성을 가지고 프로퍼티를 필드에 주입할 수 있게 되었다. @ConstructorBinding 애노테이션을 사용하면 final 필드에 대해 프로퍼티를 주입해준다.

@Getter
@RequiredArgsConstructor
@CostructorBinding
@ConfigurationProperties("app.test")
public class PropertiesTest {

    private String name;
    private List<String> list;
    
}

@ConstructorBinding을 사용하지 않음으로써 필드를 final 키워드로 구현하고 Setter를 사용하지 않게 되면서 불변성을 유지할 수 있게 되었다.

주의할 점은 @ConstructorBinding을 사용한 클래스는 스스로 프로퍼티를 주입할 수 없다. 따라서 Main 클래스 또는 Configuration 클래스에서 아래의 두 애노테이션 중 하나를 사용해서 프로퍼티를 주입한다.

  • @EnableConfigurationProperties
  • @ConfigurationPropertiesScan

@Validated

프로퍼티를 검증할 때는 @Validated 애노테이션을 클래스에 지정하면 된다. 프로퍼티를 주입받을 때 검증에서 걸리면 예외가 발생한다.

...
@ConfigurationProperties("app.test")
public class PropertiesTest {

	@NotBlank
    private String name;
    @NotBlank
    private List<String> list;
    
}

@Value VS @ConfigurationProperties

  • 유연한 바인딩
    프로퍼티 값을 객체에 바인딩할 때 Camel표기법으로 선언하고 프로퍼티 키는 카멜, 케밥 등 다양한 표기법으로 선언해서 바인딩할 수 있다.

  • 메타데이터 지원
    프로퍼티 키에 대한 정보를 메타데이터 파일로 제공한다. 이름, 타입, 디폴트값 등 힌트가 되는 정보를 얻을 수 있다.

  • SpEL(Spring Expression Language, 스프링 표현언어) 평가
    SpEL은 런타임에 객체 참조에 대해 질의하고 조작하는 기능을 지원하는 언어다. @Value만 사용 가능하다.

마무리

간단하게 변수 한 두개 정도에 프로퍼티를 바인딩하여 쓸 경우엔 @Value 어노테이션을 사용할 수 있겠으나
일반적인 케이스에서는 불변성을 유지하고 코드를 간결하게 작성할 수 있는@ConfigurationProperties와 @ConstructBinding을 같이 사용하는 것이 좋아보인다.

  • 반면, Late Binding을 위해 @Value를 사용해야 하는 경우도 발생한다. (ex. Spring Batch)

상황에 맞게 구현하는 것이 중요한 것 같다.

Reference

profile
"Hello World"

0개의 댓글