一:
Spring @Value 加载Map 结构时,报:Cannot convert value of type ‘java.util.Collections$UnmodifiableRandomAccessList’ to required type ‘java.util.Map
org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'java.util.Collections$UnmodifiableRandomAccessList' to required type 'java.util.Map'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.util.Collections$UnmodifiableRandomAccessList' to required type 'java.util.Map': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:74)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:54)
at com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener.resolvePropertyValue(AutoUpdateConfigChangeListener.java:115)
at com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener.updateSpringValue(AutoUpdateConfigChangeListener.java:90)
at com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener.onChange(AutoUpdateConfigChangeListener.java:66)
at com.ctrip.framework.apollo.internals.AbstractConfig$2.run(AbstractConfig.java:440)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.util.Collections$UnmodifiableRandomAccessList' to required type 'java.util.Map': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:306)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:125)
at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:61)
二:
Map 配置如下:
@Value("#{${small.flow.by.assign.map:null}}")
private Map<String, String> smallFlowByAssignMap;
small.flow.by.assign.map 配置的值为: { } 或者{} 等, Spring 会将 {} 转换为: List 类型,
注: List 类型的默认值是: {}
如:
@Value("#{${not.execute.new.regulation.List:{}}}")
private List<String> notExecuteNewRegulations;
跟踪源码发现:
org.springframework.expression.spel.standard.InternalSpelExpressionParser#maybeEatInlineListOrMap
@Value 中对应的属性如果值:
1:开始为
{
后面跟
}
会转换为List:
// empty list ‘{}’
2:开始为
{
后面跟
:
会转换为Map
// empty map ‘{:}’
如果需要使用@Value 声明对象属性为Map,也可以采用间接方式处理:
如 示例代码: 使用属性的set 方法注入属性时,将配置的属性声明为String 类型,然后通过Json 转换为Map类型
@Value("${small.flow.by.assign.mapStr:{}}")
public void setSmallFlowByAssignMap(String assignMapStr) {
this.smallFlowByAssignMap = json().toObject(assignMapStr, new TypeReference<Map<String, Integer>>() {
});
}
三: #{…}和${…} 用法: 参考:
https://www.cnblogs.com/candlia/p/11919934.html
#{…}和${…}
${…}用法
通过@Value(“${spelDefault.value}”)可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,则会报错。可以通过赋予默认值解决这个问题,如
@Value("${test.value:127.0.0.1}")
#{…}用法
#{…}的{}里面的内容必须符合SpEL表达式,详细的语法,以后可以专门开新的文章介绍,这里只演示简单用法:
${…}和#{…}混合使用
${…}和#{…}可以混合使用,如下文代码执行顺序:通过
${server.name}
从属性文件中获取值并进行替换,然后就变成了 执行SpEL表达式
#{'server1,server2,server3'.split(',')}
// SpEL: 传入一个字符串,根据”,”切分后插入列表中, #{}和${}配置使用(注意单引号,注意不能反过来${}在外面,#{}在里面)
@Value("#{'${server.name}'.split(',')}") private List<String> servers;
在上文中在#{}外面,${}在里面可以执行成功,那么反过来是否可以呢${}在外面,#{}在里面,是不能。
因为spring执行${}是时机要早于#{}。${}在外面,#{}在里面是非法操作。
小结
#{…} 主要用于加载外部属性文件中的值
${…} 用于执行SpEl表达式,并将内容赋值给属性
#{…} 和${…} 可以混合使用,但是必须#{}外面,${}在里面