最近在遇到一个问题,SpringBoot的yml中配置map,使用@Value注入会报错,
最开始的配置
mapping:
AAAA: AAAA
BBBB: BBBB
代码如下:
@Value("${mapping}")
private Map map;
.....
启动就会报错:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'TestController': Unsatisfied dependency expressed through field 'TestService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'TestService': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'mapping' in value "${mapping}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:662) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:642) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) ~[spring-beans-5.3.29.jar:5.3.29]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:921) ~[spring-context-5.3.29.jar:5.3.29]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.29.jar:5.3.29]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.15.jar:2.7.15]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) ~[spring-boot-2.7.15.jar:2.7.15]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.15.jar:2.7.15]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) ~[spring-boot-2.7.15.jar:2.7.15]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) ~[spring-boot-2.7.15.jar:2.7.15]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) ~[spring-boot-2.7.15.jar:2.7.15]
解决方式有两种:
1.还是@Value
yml
mapping: "{
'AAAA': 'AAAA',
'BBBB': 'BBBB'
}"
其中"和’和,都是不可省略的,少了’会当作EL表达式变量。
代码:
@Value("#{${mapping:{}}}")
private Map map;
.....
其实就是使用el表达式解析。然后程序就可以正常使用了。
2. 使用properties配置就会自动解析
app:
mapping:
AAAA: AAAA
BBBB: BBBB
@Data
@ConfigurationProperties(prefix = "app")
public class TestConfig {
private Map mapping;
}
使用的时候要加@EnableConfigurationProperties(TestConfig .class),不然程序不生效的
@Service
@EnableConfigurationProperties(TestConfig .class)
public class TestService {
@Resource
private TestConfig testConfig;
}
就可以通过config正常使用了。
yml其他格式的解析
app:
single: test
array: 111,222,333
list: 111,222,333
mapList: "{
key1: '111,222',
key2: '333,444',
key3: '555,666'
}"
/**
* 默认值是 空字符串,
* 值是yw
*/
@Value("${app.single:}")
private String str1;
/**
* 默认值是空数组 []
*/
@Value("${app.array:}")
private String[] array;
/**
* 默认值是空列表 []
*/
@Value("${app.list:}")
private List list;
/**
* 默认值是 null
*/
@Value("#{${app.mapList:{}}}")
private Map> mapList;
config的pojo配置
pojo配置其实很简单,就是将属性配置上去即可。
yml
app:
datasource:
mapDatasource:
TestDatasource1:
db-type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: ****
url: ****
username: ****
password: ****
initial-size: 5
min-idle: 5
max-active: 10
max-wait: 5000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
max-evictable-idle-time-millis: 900000
connection-error-retry-attempts: 1
break-after-acquire-failure: true
TestDatasource2:
db-type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: ****
url: ****
username: ****
password: ****
initial-size: 5
min-idle: 5
max-active: 10
max-wait: 5000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
max-evictable-idle-time-millis: 900000
connection-error-retry-attempts: 1
break-after-acquire-failure: true
代码就是注意变量名是在yml的配置而已
@Data
@ConfigurationProperties(prefix = "app.datasource")
public class SystemDynamicDatasourceProperties {
private Map mapDatasource;
}