Springboot 随笔-- Properties 配置一坑
2016-11-22 11:06
267 查看
原Spring项目迁移成SpringBoot项目,早前使用 PropertyPlaceholderConfigurer
配置properties引入,在使用properties中的配置项时报错,如 ${user.name} 配置项找不到,有时又可以但 application.properties 中配置项找不到。
要找到问题关键先要知道Spring处理配置项注入是怎么实现的。
XML注入
@Value Java代码中注入
PropertyPlaceholderConfigurer 为例,实现 BeanFactoryPostProcessor 接口所以bean
Definition 载入完毕后会被调用
在该方法中主要是遍历所有的BeanDefinition,找到那些 ${} 的配置项,然后替换掉
最后,将 StringValueResolver 加到 BeanFactory 中留作他用(如 AutowiredAnnotationBeanPostProcessor 有用,下面就分析)
所有 @Value,@Autowired 注解都是由 AutowiredAnnotationBeanPostProcessor 来实现处理的,由于实现了接口 InstantiationAwareBeanPostProcessor ,所以会自动在实例完后调用
在 metadata.inject 中主要是调用 BeanFactory 的
最终还是获取 embeddedValueResolvers 来处理
SpringBoot 默认就会注册一个 PropertySourcesPlaceholderConfigurer,当再配置一个 PropertyPlaceholderConfigurer 时就会存在两个,一部分properties在前者、一部分在后者,那么肯定会执行其中一个时报错。
在执行 resolver.resolveStringValue(result) 时,最终 PlaceholderResolvingStringValueResolver 的 helper 中
就是解析不到${}时就会报错。
将原来的 PropertySourcesPlaceholderConfigurer 去掉
改写 PropertySourcesPlaceholderConfigurer,将 Environment 加入
将两个Configurer的 ignoreUnresolvablePlaceholders 都配置成true
三种方式任选,建议(1)使用SpringBoot的最佳实践
配置properties引入,在使用properties中的配置项时报错,如 ${user.name} 配置项找不到,有时又可以但 application.properties 中配置项找不到。
要找到问题关键先要知道Spring处理配置项注入是怎么实现的。
Spring 配置项注入
1. Spring注入方式
XML注入<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="https://my.oschina.net/alexqdjay/blog/${spring.datasource.driver}"/> <property name="url" value="https://my.oschina.net/alexqdjay/blog/${spring.datasource.url}"/> <property name="username" value="https://my.oschina.net/alexqdjay/blog/${spring.datasource.username}"/> <property name="password" value="https://my.oschina.net/alexqdjay/blog/${spring.datasource.password}"/> <property name="initialSize" value="https://my.oschina.net/alexqdjay/blog/${spring.datasource.initialSize}"/> <property name="maxActive" value="https://my.oschina.net/alexqdjay/blog/${spring.datasource.maxActive}"/> <property name="maxIdle" value="https://my.oschina.net/alexqdjay/blog/${spring.datasource.maxIdle}"/> <property name="minIdle" value="https://my.oschina.net/alexqdjay/blog/${spring.datasource.minIdle}"/> <property name="maxWait" value="https://my.oschina.net/alexqdjay/blog/${spring.datasource.maxWait}"/> </bean>
@Value Java代码中注入
@Value("${user.name}") private String username;
2. 实现原理
2.1 XML
PropertyPlaceholderConfigurer 为例,实现 BeanFactoryPostProcessor 接口所以beanDefinition 载入完毕后会被调用
postProcessBeanFactory()
在该方法中主要是遍历所有的BeanDefinition,找到那些 ${} 的配置项,然后替换掉
visitor.visitBeanDefinition(bd); // 遍历BeanDefinition
最后,将 StringValueResolver 加到 BeanFactory 中留作他用(如 AutowiredAnnotationBeanPostProcessor 有用,下面就分析)
beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
2.2 @Value
所有 @Value,@Autowired 注解都是由 AutowiredAnnotationBeanPostProcessor 来实现处理的,由于实现了接口 InstantiationAwareBeanPostProcessor ,所以会自动在实例完后调用PropertyValues postProcessPropertyValues(PropertyValues var1, PropertyDescriptor[] var2, Object var3, String var4) public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { InjectionMetadata metadata = https://my.oschina.net/alexqdjay/blog/this.findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); // 注入的主逻辑 return pvs; } catch (BeanCreationException var7) { throw var7; } catch (Throwable var8) { throw new BeanCreationException(beanName,"Injection of autowired dependencies failed", var8); } }
在 metadata.inject 中主要是调用 BeanFactory 的
value = https://my.oschina.net/alexqdjay/blog/AutowiredAnnotationBeanPostProcessor.this.beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); ... field.set(bean, value);
beanFactory.resolveDependency -> beanFactory.doResolveDependency -> beanFactory.resolveEmbeddedValue public String resolveEmbeddedValue(String value) { String result = value; StringValueResolver resolver; for(Iterator var3 = this.embeddedValueResolvers.iterator(); var3.hasNext(); result = resolver.resolveStringValue(result)) { resolver = (StringValueResolver)var3.next(); if(result == null) { return null; } } return result; }
最终还是获取 embeddedValueResolvers 来处理
为什么会报错?
SpringBoot 默认就会注册一个 PropertySourcesPlaceholderConfigurer,当再配置一个 PropertyPlaceholderConfigurer 时就会存在两个,一部分properties在前者、一部分在后者,那么肯定会执行其中一个时报错。在执行 resolver.resolveStringValue(result) 时,最终 PlaceholderResolvingStringValueResolver 的 helper 中
protected String parseStringValue(String strVal, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) { ... if (value != null) { ... } else { if(!this.ignoreUnresolvablePlaceholders) { throw new IllegalArgumentException("Could not resolve placeholder \'" + placeholder + "\'" + " in string value \"" + strVal + "\""); } } }
就是解析不到${}时就会报错。
解决方法
将原来的 PropertySourcesPlaceholderConfigurer 去掉改写 PropertySourcesPlaceholderConfigurer,将 Environment 加入
将两个Configurer的 ignoreUnresolvablePlaceholders 都配置成true
三种方式任选,建议(1)使用SpringBoot的最佳实践
相关文章推荐
- SpringBoot内部配置:“application.properties配置”和”使用XML配置”,读取属性文件中的内容,日志配置,Profile配置(学习:SpringBoot实战)
- Spring boot 十四 读取 .properties 配置
- SpringBoot Properties常用应用属性配置列表
- spring boot application properties配置详解
- spring-boot配置(一):@Configuration,@ConfigurationProperties和application.yml
- Spring-Boot初学之配置文件application.properties(数据源配置)
- SpringBoot入门-20(springboot集成mybatis注解形式properties配置,利用@Provider实现动态SQL)
- spring boot-application.properties配置文件属性
- SpringBoot学习:获取yml和properties配置文件的内容
- springboot 修改默认加载的配置文件不为application.properties
- Spring Boot的properties配置文件读取
- (三)SpringBoot之配置文件详解:Properties和YAML
- spring boot 通过@Value,@ConfigurationProperties获取配置
- SpringBoot学习之配置文件注入@ConfigurationProperties
- 【springboot】之将properties配置转为bean
- springboot application.properties配置
- Spring Boot Dubbo applications.properties 配置清单
- Spring Boot核心原理-自动配置 以及@ConfigurationProperties 注解
- Spring Boot 配置文件详解:Properties和YAML
- SpringBoot 使用properties配置文件实现多环境配置