본문 바로가기
Spring/Spring Boot

@ConfigurationProperties으로 프로퍼티값 바인딩하기

by yoon_seon 2024. 2. 7.

SpringBoot 3.2.1 버전으로 진행한 내용입니다.

 

아래와 같은 properties 파일로 외부 URL을 관리하고 있다.

 

@Value

@Value 어노테이션을 사용하면 프로퍼티 파일의 값을 변수에 바인딩 할 수 있다.

 

하지만 @Value 어노테이션을 사용하면 final 키워드를 붙이지 못한다.


@Value 어노테이션은 스프링에서 프로퍼티 파일의 값을 스프링 빈으로 등록하는데 스프링 컨텍스트가 시작될 때, 즉 런타임 시점에 프로퍼티 파일에 정의된 값들이 해당 변수에 바인딩 되기 때문에 컴파일 시점에서 final 키워드를 사용할 수 없다.

따라서, @Value 어노테이션을 통해 바인딩 된 변수는 불변하게 관리할 수 없다는 치명적인 단점이 있다.

 


@PropertySource

@PropertySource 어노테이션을 사용하면 스프링에서 프로퍼티 파일의 값을 클래스 바인딩할 수 있다.

@PropertySource을 적용한 클래스 내부에서도 @Value 어노테이션을 통해서 변수에 바인딩하기 때문에 주입된 변수에 불변함을 보장하지는 못한다.
따라서 클래스 레벨에서 Setter 메서드나 생성자를 열어두지 않도록해서 외부에서 클래스 변수의 값을 변경하지 못하도록 캡슐화하여 불변 상태를 보장하도록 만들 수 있다.

스프링빈에 등록된 프로퍼티 파일의 값을 클래스로 바인딩 했기 때문에 다른 클래스에서 해당 클래스를 생성자 주입하여 사용할 수 있다.

(테스트 클래스이기 때문에 생성자에 @Autowired 어노테이션 사용하여 주입했다.)

 

하지만 여전히 @PropertySource을 적용한 클래스 내부에서는 변수 생성 시점에 final 키워드를 사용할 수 없다라는 문제점이 있다.

 


@ConfigurationProperties

@ConfigurationProperties 어노테이션은 프로퍼티 파일 값을 클래스에 바인딩 가능하다. Setter를 통해 바인딩하거나 생성자를 통해 바인딩 할 수 있다.

Setter로 바인딩하는 방법은 주입하려는 필드에 final로 선언할 수 없기 때문에 스프링 컨테이너에 의해 싱글톤으로 관리되는 객체를 불변객체로 만들 수 없다.(위에서 다룬 방법들의 문제를 해결하지 못한다.)

따라서 final 키워드를 붙여서 불변 객체로 바인딩 할 수 있는 생성자로 바인딩 방법을 사용하는 것이 좋다.

먼저, 기존에 properties 파일로 관리하던 항목들을 가독성을 위해서 yml 파일로 변경했다.(물론 properties 파일도 @ConfigurationProperties 어노테이션으로 바인딩 가능하다.)

 

아래와 같이 Inner Class를 활용해서 yml 파일 구조를 맞추어 줄 수 있다.

  • @Getter : 외부에서 객체에 바인딩 된 값을 조회할 수 있도록 추가했다.
  • @RequiredArgsConstructor : 생성자 주입을 통해 객체 값을 바인딩 하기위해 추가했다.
  • @ConfigurationProperties : prefix에 접근하려는 yml 파일 구조로 설정한다

 

@ConfigurationProperties을 통해 스프링 빈으로 등록하려면 @ConfigurationPropertiesScan 어노테이션을 추가해야한다.

@ConfigurationPropertiesScan 어노테이션은 패키지를 기반으로 @ConfigurationProperties가 등록된 클래스들을 찾아 값들을 주입하고 빈으로 등록해준다. → @ComponentScan과 유사하다.

@ConfigurationPropertiesScan 어노테이션에 value를 패키지 경로를 설정해주면 해당 패키지 하위 클래스를 스캔한다.

value를 설정하지 않으면 어노테이션이 적용된 클래스 패키지를 대상으로 하위 패키지에 등록된 @ConfigurationProperties 어노테이션을 스캔해서 스프링 빈으로 등록한다.

따라서 스프링 어플리케이션 실행 파일에 적용하여 사용할 수 있다.

 

그러면 스프링 빈으로 등록되어 생성자 주입으로 객체 바인딩이 가능하다.

 


@ConstructorBinding

@ConfigurationProperties 어노테이션은 @ConstructorBinding 어노테이션을 통해서 값을 바인딩한다.
SpringBoot 2.x에서는 클래스 레벨에 @ConstructorBinding을 추가했어야 했지만 SpringBoot 3.x는 생성자와 어노테이션 레벨에서만 @ConstructorBinding 어노테이션을 적용할 수 있도록 수정됐다.

스프링부트 3.0부터 생성자가 1개만 있는 경우에 기본적으로 생성자 방식으로 동작하기 때문에 @ConstructorBinding 어노테이션을 생략해도 값을 바인딩할 수 있다.



++++

@ConfigurationProperties로 바인딩한 클래스가 인스턴스로 생성되지 못하는 문제

위와같이 설정하여 프로젝트를 진행하던 도중 아래와 같은 에러가 발생했다.

@ConfigurationProperties를 적용한 클래스의 인스턴스를 생성했지 못했다는 내용이다.

한참을 찾다가 아래와 같은 답변을 발견할 수 있었다.

 

현재 SpringBoot 3.2.1 부터 @ConfigurationProperties 를 사용한 설정값 바인딩에 이슈가 있는것 같습니다. -

안녕하세요! 질문 내용은 제목과 같습니다. 스프링부트 3.2.1 부터 @ConfigurationProperties 가 동작하지 않는것 같습니다. 확실하지 않지만 스텍오버플로우에도 비슷한 이슈가 올라온 상태인것 같습니

www.inflearn.com

SpringBoot 3.2부터 발생한 이슈인데, 더 이상 바이트 코드를 사용하여 추론하지 않아 발생하는 듯 하다.

또한 SpringBoot3.x에서 부터는 Gradle로 빌드하는 것을 권장한다.

 

따라서 인텔리제이 빌드 설정을 Gradle로 변경하여 문제를 해결할 수 있었다.

 


참고 블로그

댓글