Spring Boot 1.x 에서 잘 사용하고 있던 RelaxedPropertyResolver가 2.0 이후 Deprecated 되었다.
Binder를 사용하는 것을 Migration Guide에서 권장하고 있다.
Spring Boot 2.0 Migration Guide #Relaxed Binding 참고
Spring Boot 1.x에서 RelaxedPropertyResolver를 사용하던 방식은 다음과 같다.
@Bean
public Map<String, Object> uiPropertiesMap(Environment environment) {
return new RelaxedPropertyResolver(environment, "ui.").getSubProperties("");
}
단순히 environment에서 특정 문자열로 시작하는 properties를 모아 Map으로 반환하는 형태이다.
2.0 이후 제공하는 Binder를 사용하면 다음과 같다.
@Bean
public Map<String, Object> uiPropertiesMap(Environment environment) {
return Binder.get(environment).bind("ui", Bindable.of(Map.class)).get();
}
하지만 기대하던 것과 결과가 다르게 나올 수도 있다.
아래와 같이 properties를 관리하고 있었다고 하면
ui.a=a value
ui.b=b value
ui.b.b1=b1 value
ui.c.c1=c1 value
ui.c.c2=c2 value
Spring Boot 1.x 에서 RelaxedPropertyResolver를 사용한 호출 결과는 아래와 같다.
{
"a" : "a value",
"b" : "b value",
"b.b1" : "b1 value",
"c.c1" : "c1 value",
"c.c2" : "c2 value"
}
Spring Boot 2.x 에서 Binder를 사용한 호출 결과는 아래와 같다.
{
"a" : "a value",
"b" : "b value",
"c" : {
"c1" : "c1 value",
"c2" : "c2 value"
}
}
기존엔 key/value 로만 일괄 처리되던 부분이 하위 Object로 맵핑되어 계층 구조로 바인딩이 되게 되었다.
하지만 이 경우 b.b1의 값이 Binder를 통한 호출 시엔 사라진다.
이유는 이미 b라는 key를 통해 "b value"라는 value가 이미 b key에 등록된 이후 동일 키에 대해 하위 계층 구조가 value에 key/value 형태로 저장하려는 경우 이미 존재한 값을 overwrite 하지 않고 넘어가기 때문이다.
반대로 b.b1을 먼저 선언한 경우라면 아래와 같이 하위 계층 구조가 바인딩되고 b key에 저장된 "b value" 라는 value가 반대로 overwrite 되지 않고 넘어가게 된다.
{
"a" : "a value",
"b" : {
"b1" : "b1 value"
},
"c" : {
"c1" : "c1 value",
"c2" : "c2 value"
}
}
binder가 좀더 구조적으로 명확하게 관리를 해주는 대신 value 위치에서 sub key와 value를 섞어 쓴 경우 이와 같은 문제가 발생한다.
key와 value의 위치를 혼합해서 사용하지 않았다면 별 문제없이 binder로 이전이 되지만 그렇지 않은 경우 어쩔 수 없이 기존 RelaxedPropertyResolver를 별도로 구현하는 형태로 사용할 수 밖에 없다.
@Bean
public Map<String, Object> uiPropertiesMap(ConfigurableEnvironment environment) {
Map<String, Object> uiPropertiesMap = new LinkedHashMap<String, Object>();
for (org.springframework.core.env.PropertySource<?> source : environment.getPropertySources()) {
if (source instanceof EnumerablePropertySource) {
for (String name : ((EnumerablePropertySource<?>) source).getPropertyNames()) {
String key = getSubKey(name, "ui.", "");
if (key != null && !uiPropertiesMap.containsKey(key)) {
uiPropertiesMap.put(key, source.getProperty(name));
}
}
}
}
return uiPropertiesMap;
}
private static String getSubKey(String name, String rootPrefix, String keyPrefix) {
if (name.startsWith(rootPrefix + keyPrefix)) {
return name.substring((rootPrefix + keyPrefix).length());
}
return null;
}
'Study > Java' 카테고리의 다른 글
RestTemplate list 반환하기 (0) | 2018.11.16 |
---|---|
자주 쓰는 spring util 기록 (0) | 2018.11.14 |
java Exception은 어떻게 사용하는게 좋을까? (0) | 2018.11.12 |
Spring Boot 2.1.0 Release (0) | 2018.10.31 |
Spring Boot 2.0 PropertyMapper 사용하기 (0) | 2018.10.24 |
Spring Boot 2.0 마일스톤 별 변경 사항 (0) | 2018.10.10 |
SpringOne Platform 2018 발표 동영상 (0) | 2018.10.06 |
[Java]Apache Commons Chain (0) | 2010.03.28 |
[JAVA][basic] mvc의 분리와 wraper 클래스의 필요성 (0) | 2009.10.05 |
[JAVA][tip] Swing JFrame의 ActionListener와 KeyListener의 처리와 통합 (0) | 2009.10.01 |