반응형

개요

properties, yml 설정 파일에 있는 설정 값을 활용하는 간단한 방법은 @Value 어노테이션을 활용하는 것이다.

//예시
@Value("${host.url}")
private String url;

문제는 사용해야 하는 설정 값이 점점 많아졌을 때 어노테이션과 프로퍼티 값이 2라인씩 차지하기 때문에 가독성도 떨어지고 비슷한 설정들을 묶어 놓는 것도 애매해지기 때문에 이럴때 pojo 형식의 ConfigurationProperties가 유용하기 때문에 한번 알아보자.

 

ConfigurationProperties 사용하기

먼저 컨피그로 활용할 객체에 @Configuration, @ConfigurationProperties와 prefix를 지정해 해당 값 이하의 설정값들을 사용한다.

@Configuration
@ConfigurationProperties(prefix = "mail")
public class ConfigProperties {
    private String hostName;
    private int port;
    private String from;
    // standard getters and setters
}

 

설정값 세팅이 끝났으면 app main 클래스에 EnableConfigurationProperties 어노테이션과 설정 클래스를 value로 집어넣는다.

@SpringBootApplication
@EnableConfigurationProperties(ConfigProperties.class)
public class EnableConfigurationDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(EnableConfigurationDemoApplication.class, args);
    }
}

 

그럼 이제 ConfigProperties는 각 컴포넌트에 의존성으로 주입해 사용할 수 있는 설정 객체로 사용 가능해진다.

 

프로퍼티로 매핑되는 설정 네이밍 규칙은 아래 예시 포멧에 대해 모두 지원한다.

mail.hostName
mail.hostname
mail.host_name
mail.host-name
mail.HOST_NAME

 

좀 더 간단하게 ConfigurationProties를 사용하는 방법

기존에는 설정값으로 활용할 객체에 ConfigurationProties와 Bean으로 생성할 수 있는 어노테이션(@Configuration, @Component 등)을 달고 EnableConfigurationProperties 어노테이션에 해당 클래스를 입력해야 했다.

설정 객체가 많아지다보면 Enable 어노테이션에 설정값 객체 클래스들을 붙여나가는 것도 가독성이 떨어지고 귀찮아지기 때문에 스프링 부트 2.2 버전 이상부터는 다음과 같이 좀 더 쉽게 사용할 수 있게 되었다.

 

1. 컨피그 클래스

@ConfigurationProperties(prefix = "mail") 
public class ConfigProperties { 
    private String hostName; 
    private int port; 
    private String from; 
    // standard getters and setters 
}

 

2. 컴포넌트 클래스

@SpringBootApplication
@ConfigurationPropertiesScan
public class EnableConfigurationDemoApplication { 
    public static void main(String[] args) {   
        SpringApplication.run(EnableConfigurationDemoApplication.class, args); 
    } 
}

스프링 서버 구동시 ConfigurationPropertiesScan가 존재하는 패키지 이하에서 프로퍼티 스캔을 진행하게 된다.

그래서 꼭 메인 클래스가 아니더라도 프로퍼티 클래스와 동일한 패키지나 상위 패키지의 컴포넌트 객체에 설정해도 된다.

또한, @ConfigurationPropertiesScan("com.example.demo.mail") 같은 형태로 프로퍼티 스캔을 할 루트 패키지를 지정할 수도 있다.

여기서 프로퍼티 스캔시 프로퍼티 클래스를 @Configuration, @Component 어노테이션 같이 Bean으로 설정하는 경우 프로퍼티 스캔에 포함되지 않는다.

 

Nested Properties

스프링에서는 중첩 프로퍼티를 설정 객체에 넣어 사용할 때 Map, List, Object 타입을 각각 지원한다.

다음 예제에서 Credentials 객체와 해당 객체를 갖는 ConfigProperties에 컨피그 값을 설정해본다.

public class Credentials {
    private String authMethod;
    private String username;
    private String password;

    // standard getters and setters
}

public class ConfigProperties {

    private String hostname;
    private int port;
    private String from;
    private List<String> defaultRecipients;
    private Map<String, String> additionalHeaders;
    private Credentials credentials;
 
    // standard getters and setters
}
#Simple properties
mail.hostname=mailer@mail.com
mail.port=9000
mail.from=mailer@mail.com

#List properties
mail.defaultRecipients[0]=admin@mail.com
mail.defaultRecipients[1]=owner@mail.com

#Map Properties
mail.additionalHeaders.redelivery=true
mail.additionalHeaders.secure=true

#Object properties
mail.credentials.username=john
mail.credentials.password=password
mail.credentials.authMethod=SHA1
  • 가장 간단한 String, int 값부터 array 타입으로 넣거나 map, 객체 내부의 프로퍼티로 설정할 수 있는 걸 볼 수 있다.

 

@Bean 어노테이션에 ConfigurationProperties 적용하기

설정 값으로 사용하고자 하는 클래스가 내 프로젝트가 아닌 서드 파티 컴포넌트에 포함돼 있는 경우에 유용하다.

public class Item {
    private String name;
    private int size;

    // standard getters and setters
}

@Configuration
public class ConfigProperties {

    @Bean
    @ConfigurationProperties(prefix = "item")
    public Item item() {
        return new Item();
    }
}

 

ConfigurationProperties 불변 객체로 활용하기

@ConstructorBinding

어노테이션을 생성자에 사용하면 setter를 모두 삭제하고 immutable 객체로 사용할 수 있다.

@ConfigurationProperties(prefix = "mail.credentials")
public class ImmutableCredentials {

    private final String authMethod;
    private final String username;
    private final String password;

    @ConstructorBinding
    public ImmutableCredentials(String authMethod, String username, String password) {
        this.authMethod = authMethod;
        this.username = username;
        this.password = password;
    }

    public ImmutableCredentials(String username, String password) {
        this.username = username;
        this.password = password;
        this.authMethod = "Default";
    }
    public String getAuthMethod() {
        return authMethod;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}

자바 16 버전부터 사용가능한 record 타입을 활용하기

  • 객체의 상태 값을 변경할 경우 다양한 사이드 이펙트가 발생할 수 있기 때문에 코틀린 데이터 클래스 같은 immutable한 record 타입이 자바에 도입 되었는데 이 record 타입에도 컨피그 값으로 사용할 수 있다.
@ConstructorBinding
@ConfigurationProperties(prefix = "mail.credentials")
public record ImmutableCredentials(String authMethod, String username, String password) {
}

 

기타

configuration 값에 대해서 어노테이션 기반으로 해당 설정이 올바른 값인지 체크하는 기능도 있다.

그 기능이 사용하고자 한다면 해당 의존성을 주입하고

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

하단 참고 자료의 링크를 따라가서 활용해보자.

 

참고 자료

반응형