如何将ConfigMap中的Map直接注入Spring Boot应用?
问题描述
我在Helm的values.yaml中配置了如下Map结构:
defaultview: journey: ce5f164c-ae0f-11e7-9220-c7137b83fb6a: 45 abc: -1 pqr: 30
在ConfigMap模板中读取该属性时使用了:
defaultview.journey: {{ .Values.defaultview.journey }}
最终生成的ConfigMap里该条目显示为:
defaultview.journey: ---- map[abc:-1 ce5f164c-ae0f-11e7-9220-c7137b83fb6a:45 pqr:30]
我尝试通过Spring Boot配置类将该属性绑定为Map<String,Integer>:
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; @Data @Component @ConfigurationProperties(prefix = "defaultview") public class JourneyViewConfig { private Map<String, Integer> journey = new HashMap<>(); }
但启动时抛出类型转换错误:
Failed to bind properties under 'defaultview.journey' to java.util.Map<java.lang.String, java.lang.Integer>: Property: defaultview.journey Value: "map[abc:-1 ce5f164c-ae0f-11e7-9220-c7137b83fb6a:45 pqr:30]" Origin: "defaultview.journey" from property source "<cm name>" Reason: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<java.lang.String, java.lang.Integer>
目前我通过临时代码实现了解析,但想寻求更优雅的直接注入方式。
解决方案
方法1:修正Helm模板输出格式(推荐)
问题根源是Helm直接输出了Go语言风格的map字符串,Spring Boot无法识别这种格式。需要让ConfigMap输出Spring能解析的YAML/Properties格式的Map,有两种可行写法:
写法A:用toYaml函数转换为标准YAML格式
修改ConfigMap模板:
defaultview.journey: |- {{- .Values.defaultview.journey | toYaml | nindent 2 }}
生成的ConfigMap会变成:
defaultview.journey: abc: -1 ce5f164c-ae0f-11e7-9220-c7137b83fb6a: 45 pqr: 30
这种标准YAML Map格式可以被Spring Boot的@ConfigurationProperties直接绑定,无需额外处理。
写法B:展开Map为键值对(适配Properties格式场景)
如果需要用Properties格式输出,可遍历Map的键值对:
{{- range $key, $val := .Values.defaultview.journey }} defaultview.journey.{{ $key }}: {{ $val }} {{- end }}
生成的ConfigMap会是:
defaultview.journey.abc: -1 defaultview.journey.ce5f164c-ae0f-11e7-9220-c7137b83fb6a: 45 defaultview.journey.pqr: 30
这种格式同样能被@ConfigurationProperties直接绑定到Map<String, Integer>。
方法2:自定义Spring类型转换器(仅当无法修改Helm模板时使用)
如果无法调整Helm模板,只能处理Go风格的map[...]字符串,可以自定义一个类型转换器:
import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @Component public class GoMapToJavaMapConverter implements Converter<String, Map<String, Integer>> { private static final Pattern MAP_PATTERN = Pattern.compile("map\\[(.*?)\\]"); private static final Pattern ENTRY_PATTERN = Pattern.compile("(\\S+?):(-?\\d+)"); @Override public Map<String, Integer> convert(String source) { Map<String, Integer> result = new HashMap<>(); Matcher mapMatcher = MAP_PATTERN.matcher(source); if (mapMatcher.find()) { String entriesStr = mapMatcher.group(1); Matcher entryMatcher = ENTRY_PATTERN.matcher(entriesStr); while (entryMatcher.find()) { String key = entryMatcher.group(1); Integer value = Integer.parseInt(entryMatcher.group(2)); result.put(key, value); } } return result; } }
注册该转换器后,Spring会自动用它将defaultview.journey的字符串值解析为Map。
注意:这种方法依赖Go的map字符串格式,一旦格式变更就会失效,因此优先推荐方法1。
内容的提问来源于stack exchange,提问作者Prashant Raghav
相关产品推荐
相关产品推荐

