@ConfigurationProperties Annotation
0. 들어가면서
application.yml 설정에 등록한 값들을 리스트(list)로 사용하는 방법에 대해 정리하였습니다.
1. @Value Anntation
설정 값을 주입 받는 방법 중 가장 흔히 사용됩니다.
SpEL(Spring Exression Language) 규칙을 사용하면 더 다양한 형식으로 설정 값을 받을 수 있습니다.
이번 포스트에선 단순하게 리스트로만 값을 주입 받았습니다.
1.1. application-value.yml
- 다음과 같이 호스트 정보들이 쉼표로 구분되어 있습니다.
redis:
sentinels: http://sentinel-1:8080,http://sentinel-2:8081,http://sentinel-3:8082
1.2. ValueApplicationTests Class
@Value애너테이션을 사용해 설정 값들을 주입 받습니다.- 키(key) 하나에 매칭된 여러 설정 값들을 쉼표(,)로 구분한 경우 배열(array)나 리스트로 주입 받을 수 있습니다.
SpEL을 사용하면 특정한 문자나 정규식 패턴을 통해 설정 값을 분리 후 주입 받을 수 있습니다.
package action.in.blog;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@SpringBootTest(properties = {"spring.profiles.active=value"})
class ValueApplicationTests {
@Value("${redis.sentinels}")
String[] sentinels;
@Value("#{'${redis.sentinels}'.split(',')}")
List<String> sentinelsWithSplitter;
private String[] getHostAndPort(String sentinel) {
int lastIndex = sentinel.lastIndexOf(":");
return new String[]{sentinel.substring(0, lastIndex), sentinel.substring(lastIndex + 1)};
}
@Test
void get_string_array_from_application_yml() {
assertThat(sentinels.length, equalTo(3));
String[] firstSentinel = getHostAndPort(sentinels[0]);
assertThat(firstSentinel[0], equalTo("http://sentinel-1"));
assertThat(firstSentinel[1], equalTo("8080"));
String[] secondSentinel = getHostAndPort(sentinels[1]);
assertThat(secondSentinel[0], equalTo("http://sentinel-2"));
assertThat(secondSentinel[1], equalTo("8081"));
String[] thirdSentinel = getHostAndPort(sentinels[2]);
assertThat(thirdSentinel[0], equalTo("http://sentinel-3"));
assertThat(thirdSentinel[1], equalTo("8082"));
}
@Test
void get_string_list_from_application_yml() {
assertThat(sentinelsWithSplitter.size(), equalTo(3));
String[] firstSentinel = getHostAndPort(sentinelsWithSplitter.get(0));
assertThat(firstSentinel[0], equalTo("http://sentinel-1"));
assertThat(firstSentinel[1], equalTo("8080"));
String[] secondSentinel = getHostAndPort(sentinelsWithSplitter.get(1));
assertThat(secondSentinel[0], equalTo("http://sentinel-2"));
assertThat(secondSentinel[1], equalTo("8081"));
String[] thirdSentinel = getHostAndPort(sentinelsWithSplitter.get(2));
assertThat(thirdSentinel[0], equalTo("http://sentinel-3"));
assertThat(thirdSentinel[1], equalTo("8082"));
}
}
1.3. Pain Point of @Value Annotation for Multiple Values
@Value 애너테이션을 사용한 방법은 다음과 같은 불편함이 있습니다.
- 값이 긴 경우 항목이 많다면 옆으로 길어지기 때문에
application.yml의 가독성이 떨어집니다. - 문자열을 다시 파싱(parsing)해서 사용해야 합니다.
- 예상치 못한 버그나 에러가 발생할 수 있습니다.
- 포트 번호처럼 정수인 경우 파싱된 데이터를 다시 형변환해야 합니다.
2. @ConfigurationProperties Annotation
@ConfigurationProperties 애너테이션을 사용하면 더 나은 방법으로 값을 주입 받을 수 있습니다.
2.1. application-config.yml
- 다음과 같은 방법으로 여러 개의 호스트 정보들을 구분합니다.
redis:
sentinels:
- host: http://sentinel-1
port: 8080
- host: http://sentinel-2
port: 8081
- host: http://sentinel-3
port: 8082
2.2. SentinelConfiguration Class
application.yml 설정 파일에 명시된 키를 클래스 필드와 동일한 이름으로 지정하면 설정 값들을 객체 모습으로 사용할 수 있습니다.
- 객체 멤버 변수에 값을 주입 받거나 사용하려면
Getter,Setter메소드가 필요합니다. @Profile애너테이션을 통해 프로파일이config인 경우에만 빈을 생성합니다.- 이번 포스트의 테스트를 위한 설정입니다.
@Configuration애너테이션을 통해 설정 관련된 빈 객체로 지정합니다.@ConfigurationProperties애너테이션을 통해 주입 받기 원하는 데이터의 키 값을 접두사(prefix)로 지정합니다.redis키 하위에 존재하는sentinels키와 매칭된 클래스 필드를 작성합니다.sentinels이라는 이름을 가진 필드를 생성합니다.SentinelInstance객체를 리스트로 주입 받습니다.
sentinels키 하위에 존재하는host,port키와 매칭된 클래스 필드를 작성합니다.SentinelInstance클래스에host,port라는 이름을 가진 필드들을 생성합니다.host값은 문자열,port값은 정수로 주입 받습니다.
package action.in.blog.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import java.util.List;
@Profile("config")
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "redis")
public class SentinelConfiguration {
private List<SentinelInstance> sentinels;
@Getter
@Setter
public static class SentinelInstance {
private String host;
private int port;
}
}
2.3. ConfigurationPropertiesApplicationTests Class
- 주입 받은 객체의 센티널 정보 리스트 사이즈를 확인합니다.
- 각 센티널 정보가 정상적으로 주입되었는지 확인합니다.
package action.in.blog;
import action.in.blog.config.SentinelConfiguration;
import action.in.blog.config.SentinelConfiguration.SentinelInstance;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@SpringBootTest(properties = {"spring.profiles.active=config"})
class ConfigurationPropertiesApplicationTests {
@Autowired
SentinelConfiguration sentinelConfiguration;
@Test
void get_sentinel_from_yml_using_bean() {
List<SentinelInstance> sentinelInstances = sentinelConfiguration.getSentinels();
assertThat(sentinelInstances.size(), equalTo(3));
SentinelInstance firstInstance = sentinelInstances.get(0);
assertThat(firstInstance.getHost(), equalTo("http://sentinel-1"));
assertThat(firstInstance.getPort(), equalTo(8080));
SentinelInstance secondInstance = sentinelInstances.get(1);
assertThat(secondInstance.getHost(), equalTo("http://sentinel-2"));
assertThat(secondInstance.getPort(), equalTo(8081));
SentinelInstance thirdInstance = sentinelInstances.get(2);
assertThat(thirdInstance.getHost(), equalTo("http://sentinel-3"));
assertThat(thirdInstance.getPort(), equalTo(8082));
}
}
댓글남기기