본문 바로가기

STUDY/Spring

Spring Boot | @ConfigurationProperties 알아보기

profiles 설정과 함께라면 완벽하게 환경별로 설정값을 나눌 수 있게된다..!

@ConfigurationProperties

스프링 부트는 properties파일이나 YAML파일, 환경변수를 통해 애플리케이션에서 사용하는 설정 값을 정의할 수 있다.
propertiesYAML에 정의된 속성들은 @Value 애노테이션으로 필드(변수)에 직접 주입할 수도 있지만 @ConfigurationProperties애노테이션을 사용하면 속성들을 객체화 하여 사용할 수 있다. (Java Bean 형식으로 만든다)

@Value는 단순한 속성값을 사용할 때는 편리할 수 있지만, 속성값이 계층 구조를 가지거나 사용해야 할 속성의 개수가 많아지면 번거로워진다.

어떻게 사용하나

우선 application.propertiesapplication.yml에 사용하고자 하는 속성값을 정의한다.
아래와 같이 file > location의 계층구조를 갖는 속성값을 정의했다.

# application.yml

file:
  upload-location: /Users/username/Desktop
  download-location: /Users/username/Download

그리고 @ConfigurationProperties 애노테이션을 사용하여 속성값들을 JavaBean형식으로 바인딩한다.

  • prefix는 속성값의 공통된 key를 적어준다 (prefix =를 생략하고 바로 값을 적어도 됨)
  • kebab-case로 작성된 값은 자동으로 calmelCase로 사용할 수 있다
  • @ConstructorBinding애노테이션을 사용하면, 변경 불가능한 방식으로 작성할 수도 있다
@ConfigurationProperties(prefix = "file") 
public class PathProperties { 

    private String uploadLocation; 
    private String downloadLocation; 

    // getter와 setter 메서드를 정의해야 한다.

}

부트 애플리케이션 실행 부분에 @EnableConfigurationProperties 애노테이션을 이용해 위에서 사용할 클래스를 등록한다.

@EnableConfigurationProperties({  
    PathProperties.class  
})  
@SpringBootApplication  
public class Application {
        // 생략
}

그리고 의존성 주입 방법으로 사용하면 된다!

 

 


@Value@ConfigurationProperties의 차이

  • @ConfigurationProperties는 속성 이름과 완벽히 일치하지 않아도 된다 (유연하게 매칭시켜줌)
  • @Value는 소문자만 사용하는 kebab-case를 사용해야만 한다
  • @ValueSpEL을 사용할 수 있지만 @ConfigurationProperties는 사용할 수 없다

+) 참고

 

Spring Boot Features

Graceful shutdown is supported with all four embedded web servers (Jetty, Reactor Netty, Tomcat, and Undertow) and with both reactive and Servlet-based web applications. It occurs as part of closing the application context and is performed in the earliest

docs.spring.io


객체로 받아오기

아래처럼 api > kakao > base-url, account > id, password 이런 형태의 값을 받아오고자 할 때 객체로 받아오면 편하다.
ConfigurationProperties 사용의 장점이기도 함

api:
 kakao:
  base-url: https://어쩌구저쩌구
  account:
    id: foo
    password: bar

이런식으로 내부에 정적 클래스를 사용해 객체를 생성하여 받아오면 된다!

@ConfigurationProperties(prefix = "api")
@ConstructorBinding
public class ApiProperties {

    private final Kakao KAKAO;

    public Kakao getKAKAO() {
        return KAKAO;
    }

    public ApiProperties(Kakao KAKAO) {
        this.Kakako = KAKAO;
    }

    @Getter
    @RequiredArgsConstructor
    public static class Kakao {
        private final String baseUrl;
        private final Account account;
    }

    @Getter
    @RequiredArgsConstructor
    public static class Account {
        private final String id;
        private final String password;
    }

}