Spring Boot 의 @ConfigurationProperties

Spring Boot 의 @ConfigurationProperties

@ConfigurationProperties 는 Spring Boot 에서 properties 파일에 정의된 프로퍼티 중 주어진 prefix 를 가지는 프로퍼티들을 POJO 에 매핑하여 Bean 으로 만들수 있게 해주는 어노테이션이다.

그럼 @ConfigurationProperties 의 다양한 쓰임새에 대해 알아보자.

단순한 형태의 Property

@Configuration
@ConfigurationProperties(prefix = "mail")
public class ConfigProperties {

private String hostName;
private int port;
private String from;

// standard getters and setters
}

스프링이 Bean 을 application context 에 만들도록 @Configuration 을 꼭 같이 붙여줘야하며,
만약 붙이지 않았을 경우에는 main Spring application 클래스에 @EnableConfigurationProperties(ConfigProperties.class) 를 붙여줘야한다.

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

스프링은 프로퍼티를 바인딩할 때 완화된 규칙을 적용하여 다음과같은 변형도 모두 같게 취급한다

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

Spring Boot 2.2

스프링 부트 2.2 에서는 @ConfigurationProperties 클래스들을 모두 찾아서 등록해주므로
@Component, 혹은 @Configuration 과 같은 어노테이션이나 @EnableConfigurationProperties 를 붙일 필요가 없다.

중첩 Property

기본 자료형 뿐만 아니라 List, Map, Class 도 만들 수가 있다.
다음과 같은 클래스가 있을 때,

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

// standard getters and setters
}

다음과 같은 ConfigProperties 클래스에 프로퍼티를 바인딩 하려면

public class ConfigProperties {

private String host;
private int port;
private String from;
private List<String> defaultRecipients;
private Map<String, String> additionalHeaders;
private Credentials credentials;

// standard getters and setters
}

다음과 같은 형태로 properties 를 작성하면 된다.

#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

@Bean 메소드에 사용하기

POJO 뿐만 아니라 @Bean 어노테이션이 붙은 메소드에도 사용할 수 있다.
우리가 코드를 수정할 수 없는(어노테이션을 붙일 수 없는) 써드파티 컴포넌트에 바인딩할 때 유용하다.
예를 들어 다음과 같은 이미 컴파일된 클래스가 있을 때

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

// standard getters and setters
}

다음과 같이 @Bean 이 붙은 메소드에 @ConfigurationProperties 를 붙이면

@Configuration
public class ConfigProperties {

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

메소드의 리턴 타입인 Item 객체에 바인딩된다.

Property 유효성 검사

아래와 같이 빈 문자열 검사, 문자열 길이 범위, 정수 범위, 정규표현식을 통한 문자열의 형태를 체크할 수 있다.

@NotBlank
private String hostName;

@Length(max = 4, min = 1)
private String authMethod;

@Min(1025)
@Max(65536)
private int port;

@Pattern(regexp = "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,6}$")
private String from;

만약 유효성 검사가 실패하면 IllegalStateException 이 발생하여 main application 의 실행이 실패한다.

Property 변환

Duration, DataSize 와 같은 타입은 스프링이 자동으로 변환해준다.

Duration

Duration 은 시간을 나타내는 타입이다. 다음과 같은 Configuration 클래스가 있다고 가정하자.

@ConfigurationProperties(prefix = "conversion")
public class PropertyConversion {

private Duration timeInDefaultUnit;
private Duration timeInNano;
...
}

그럼, 다음과 같이 바인딩 할 수 있다.

conversion.sizeInDefaultUnit=300
conversion.sizeInGB=2GB
conversion.sizeInTB=4

default 단위는 ms 이며, 만약 이를 바꾸려면 @DurationUnit 을 사용한다

DataSize

DataSize 는 파일의 크기를 나타내는 타입이다. 다음과 같은 configuration 클래스가 있다고 가정하자.

private DataSize sizeInDefaultUnit;

private DataSize sizeInGB;

@DataSizeUnit(DataUnit.TERABYTES)
private DataSize sizeInTB;

그럼 다윽뫄 같이 바인딩 할 수 있다.

conversion.sizeInDefaultUnit=300
conversion.sizeInGB=2GB
conversion.sizeInTB=4

default 단위는 byte 이며, 이를 바꾸려면 @DataSizeUnit 을 사용한다

Custom Converter

커스텀 변환을 정의할 수도 있다. 다음과 같은 클래스에

public class Employee {
private String name;
private double salary;
}

다음과 같이 바인딩 하려면

conversion.employee=john,2000

다음과 같은 커스텀 Converter 클래스를 정의하면 될것이다.

@Component
@ConfigurationPropertiesBinding
public class EmployeeConverter implements Converter<String, Employee> {

@Override
public Employee convert(String from) {
String[] data = from.split(",");
return new Employee(data[0], Double.parseDouble(data[1]));
}
}

@ConstructorBinding

스프링 부트 2.2 부터 @ConstructorBinding 을 붙여서 configuration properties 를 바인딩할 수 있다.
이것은 곧 @ConfigurationProperties 이 붙은 클래스가 이제 Immutable 일 수 있다는 것을 의미한다.

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

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

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

public String getAuthMethod() {
return authMethod;
}

public String getUsername() {
return username;
}

public String getPassword() {
return password;
}
}

생성자에는 우리가 비인딩 하고자 하는 프로퍼티를 모두 인자로 가져야 한다.
위의 ImmutableCredentials 클래스는 모든 필드가 final 이기때문에 setter 가 없다.
또한, 생성자로 프로퍼티를 바인딩 하기 위해서는 @EnableConfigurationProperties, 혹은
@ConfigurationPropertiesScan 를 사용하여 명시적으로 configuration 클래스 를 활성화 시켜줘야 한다.

참고: https://www.baeldung.com/configuration-properties-in-spring-boot

Comments