问题描述
最近在遇到一个问题,SpringBoot的yml中配置map,使用@Value注入会报错,
最开始的配置
mapping: AAAA: AAAA BBBB: BBBB
代码如下:
@Value("${mapping}") private Map<String, String> 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<String, String> map; .....
其实就是使用el表达式解析。然后程序就可以正常使用了。
2. 使用properties配置就会自动解析
- 代码
app: mapping: AAAA: AAAA BBBB: BBBB
- 配置config
@Data @ConfigurationProperties(prefix = "app") public class TestConfig { private Map<String,String> 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<String> list; /** * 默认值是 null */ @Value("#{${app.mapList:{}}}") private Map<String,List<String>> 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<String, DruidDataSource> mapDatasource; }