在Spring 5.1.0中加载和在属性源之间切换的最优雅的方法是什么?

时间:2018-12-18 04:58:59

标签: java spring spring-boot

我想在运行时加载和切换属性源,以读取不同的属性值,但是在应用程序中具有相同的属性键。

属性文件如下:

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文件加载会更好吗?有什么建议吗?

1 个答案:

答案 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}")来获取属性值。