@Value注入Properties 使用错误的案例
程序员文章站
2022-05-03 15:33:22
...
最近有朋友问@Value注入Properties数据注入不进去,接下来我就分析一下为什么。
场景:
需要注入Properties的value数据到Bean或方法参数。
准备数据:
<bean id="props" class="java.util.Properties"> <constructor-arg index="0"> <props> <prop key="a">123</prop> </props> </constructor-arg> </bean> <bean id="map" class="java.util.HashMap"> <constructor-arg index="0"> <map> <entry key="a" value="234"/> </map> </constructor-arg> </bean>
失败的做法:
@Value("#{props['a']}") private String propsA;
此时无法获取props的a这个键对应的值。
正确的做法:
@Value("#{props.getProperty('a')}") private String propsA; @Value("#{map['a']}") private String mapA; @RequestMapping(value="/value2") public String test2(@Value("#{props.getProperty('a')}") String propsA, @Value("#{map['a']}") String mapA) {
为什么?最后探讨。
最好的正确做法:
<util:properties id="props2"> <prop key="a">123</prop> </util:properties>
//该标签内部使用org.springframework.beans.factory.config.PropertiesFactoryBean FactoryBean实现;
@Value("#{props2['a']}") String props2A,
注入数据直接使用props[key]即可。
why?
为什么如下方式不行:
<bean id="props" class="java.util.Properties"> <constructor-arg index="0"> <props> <prop key="a">123</prop> </props> </constructor-arg> </bean>
而如下这种方式行呢?
<util:properties id="props2"> <prop key="a">123</prop> </util:properties>
原因很简单:API不熟造成的:
1、首先我们来看下Properties构造器定义:
javadoc 写道
public Properties(Properties defaults)创建一个带有指定默认值的空属性列表。
参数:
defaults - 默认值。
参数:
defaults - 默认值。
1)、构造器第一个参数是默认值;
2)、当我们使用getProperty(key) 时,首先查自己的prop,如果有直接返回,否则查defaults中的key。
javadoc 写道
public String getProperty(String key)
用指定的键在此属性列表中搜索属性。如果在此属性列表中未找到该键,则接着递归检查默认属性列表及其默认值。如果未找到属性,则此方法返回 null。
用指定的键在此属性列表中搜索属性。如果在此属性列表中未找到该键,则接着递归检查默认属性列表及其默认值。如果未找到属性,则此方法返回 null。
3)、原因到此很明显了,此时我们使用#{props.getProperty('a')} 其实是查的defaults
4)、Properties本身继承了Hashtable,其实是一种错误的用法,造成了我们现在的我们现在的问题,get(key)只查自己,而getProperty会先查自己 再查defaults。
2、而使用<util:properties id="props2"> 本身是一个FactoryBean,帮我们创建没有我们真实需要的properties。有兴趣可以看下源代码。
总结:
1、API不熟造成了错误理解(以为类似于如集合框架是做拷贝);
2、Properties继承Hashtable本身就是一种错误的继承,形成两套不同的API。
推荐阅读