我想在运行时加载和切换属性源,以读取不同的属性值,但是在应用程序中具有相同的属性键。
属性文件如下:
A.properties
key1=ValueA1
key2=ValueA2
B.properties
key1=ValueB1
key2=ValueB2
根据他们的official document
我通过以下方法解决了我的问题:
@PropertySource(value = "classpath:MessageMappingA.properties", encoding = "UTF-8", name = "A")
@PropertySource(value = "classpath:MessageMappingB.properties", encoding = "UTF-8", name = "B")
和
@Autowired
Environment env;
@Autowired
ConfigurableApplicationContext ctx;
public void setA() {
ctx.getEnvironment().getPropertySources().addFirst(ctx.getEnvironment().getPropertySources().get("A"));
}
public void setB() {
ctx.getEnvironment().getPropertySources().addFirst(ctx.getEnvironment().getPropertySources().get("B"));
}
这看起来很丑陋,我怀疑是否真的有必要将这些属性源存储在List中,并使用addFirst()对它们进行重新排序以设置源的最高优先级。按原样使用.properties文件加载会更好吗?有什么建议吗?
答案 0 :(得分:1)
根据文档。
执行的搜索是分层的...
默认情况下,系统属性优先于环境变量
要覆盖已加载的属性,必须将要使用的属性设置为最高优先级。要按照规范执行此操作,就是使用propertySouce调用propertySources.addFirst(new MyPropertySource());
方法。
现在回到您的示例。
@PropertySource(value = "classpath:MessageMappingA.properties", encoding = "UTF-8", name = "A")
@PropertySource(value = "classpath:MessageMappingB.properties", encoding = "UTF-8", name = "B")
上面的代码将最后加载属性B,这意味着如果属性B具有相同的键,则将加载它们。
MessageMappingA.properties
currency=R
MessageMappingB.properties
currency=$
注入@Value("${currency}")
时,MessageMappingB将优先,其值为$。
如果要注入/覆盖MessageMappingA的属性,则必须以最高优先级将其加载到环境的属性源中。
public void setA() throws IOException {
EncodedResource encodedResource = new EncodedResource(new ClassPathResource("MessageMappingA.properties"));
ResourcePropertySource resourcePropertySource = new ResourcePropertySource(encodedResource);
MutablePropertySources propertySources = this.environment.getPropertySources();
propertySources.addFirst(resourcePropertySource);
}
或
public void setA() {
this.environment.getPropertySources().addFirst(this.environment.getPropertySources().get("A"));
}
但是有一个陷阱。
bean的默认范围是单例。 MessageMappingA.properties的属性不会被注入到@Scope("singleton")
类型的Bean中,因为一旦初始化了Bean,MessageMappingB属性就会被注入。
您需要确保要使用新属性值的bean在每次调用时都将其注入。即使使bean @Scope("prototype")
也不起作用,因为正在调用它的上游bean可能属于@Scope("singleton")
。
当在运行时加载不同的属性源以覆盖属性时,我建议使用environment.getProperty(key)
而不是@Value("${the.key}")
来获取属性值。