![](/img/trans.png)
[英]Spring Boot EnvironmentPostProcessor not loading application.properties
[英]Spring Boot: Attempting to override application.properties using EnvironmentPostProcessor
所以我試圖使用存儲在 Cosul 中的鍵/值來覆蓋 application.properties 中的值。 我嘗試了兩件事。
1) 使用 Spring 雲領事配置。 https://cloud.spring.io/spring-cloud-consul/reference/html/#spring-cloud-consul-config
如果我的 application.properties 中沒有定義相同的鍵,這將起作用。 如果它是在 application.properties 中定義的,則屬性文件中的值將用於所有 @Value 注釋解析。 這與我想要的相反。
2)由於上面沒有工作,我繼續創建一個自定義的EnvironmentPostProcessor。 我首先嘗試構建一個 MapPropertySource 並使用 environment.getPropertySources().addAfter(..)。 這與上面的結果相同。 然后我嘗試遍歷所有屬性源,找到名稱包含“applicationConfig:[classpath:/application”的屬性源,並設置屬性值(如果存在)或放置一個新的屬性值。 此外,我將 MapPropertySource 添加到“applicationConfig: [classpath:/application” 屬性源所在的 EnumerableCompositePropertySource 中。
無論采用哪種方法,結果總是相同的。 如果 key 存在於 application.properties 中,則使用該值。
是什么賦予了? 我實際上是在覆蓋屬性源中的值,並且在 PostProcessor 完成它的工作之前,我可以在調試器中看到這些值。 application.properties 值如何仍然到達@Value 注釋?
這是我當前的后處理器。
@Order(Ordered.LOWEST_PRECEDENCE)
public class ConsulPropertyPostProcessor implements EnvironmentPostProcessor {
private static final String PROPERTY_SOURCE_NAME = "applicationConfigurationProperties";
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
PropertySource<?> system = environment.getPropertySources().get(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
ConsulKVService consulKVService = new ConsulKVServiceImpl().instantiateConsulKVServiceImpl((String)system.getProperty("CONSUL_HOST"), (String)system.getProperty("CONSUL_TOKEN"));
Map<String, Object> map = consulKVService.getConsulKeysAndValuesByPrefix((String)system.getProperty("CONSUL_PREFIX"));
addOrReplace(environment.getPropertySources(), map);
}
private void addOrReplace(MutablePropertySources propertySources, Map<String, Object> map) {
MapPropertySource target = new MapPropertySource("applicationConfig: [consulKVs]", map);
if (propertySources.contains(PROPERTY_SOURCE_NAME)) {
PropertySource<?> applicationConfigurationPropertySources = propertySources.get(PROPERTY_SOURCE_NAME);
for(EnumerableCompositePropertySource applicationPropertySource : (ArrayList<EnumerableCompositePropertySource>)applicationConfigurationPropertySources.getSource()){
if(applicationPropertySource.getName() != null
&& applicationPropertySource.getName().contains("applicationConfig: [profile=")) {
for(PropertySource singleApplicationPropertySource : applicationPropertySource.getSource()){
if(singleApplicationPropertySource.getName().contains("applicationConfig: [classpath:/application")){
for (String key : map.keySet()) {
if(map.get(key) != null) {
if (singleApplicationPropertySource.containsProperty(key)) {
((Properties) singleApplicationPropertySource.getSource())
.setProperty(key, (String) map.get(key));
} else {
((Properties) singleApplicationPropertySource.getSource()).put(key, (String) map.get(key));
}
}
}
break;
}
}
applicationPropertySource.add(target);
break;
}
}
}
}
}
提前謝謝大家。
編輯:嘗試覆蓋 ApplicationListener class 的 onApplicationEvent 方法,結果與上述相同。 這是那個代碼。
@Log4j
public class ConsulProperties implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
static ConfigurableEnvironment configurableEnvironment;
private static final String PROPERTY_SOURCE_NAME = "applicationConfigurationProperties";
public static ConfigurableEnvironment getConfigurableEnvironment() {
return configurableEnvironment;
}
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
log.info("Received ApplicationEnvironmentPreparedEvent...");
ConfigurableEnvironment environment = event.getEnvironment();
configurableEnvironment = environment;
Properties props = new Properties();
ConsulKVService consulKVService = new ConsulKVServiceImpl()
.instantiateConsulKVServiceImpl((String) configurableEnvironment.getProperty("CONSUL_HOST"),
(String) configurableEnvironment.getProperty("CONSUL_TOKEN"));
Map<String, Object> map = consulKVService.getConsulKeysAndValuesByPrefix((String) configurableEnvironment.getProperty("CONSUL_PREFIX"));
while(map.values().remove(null));
addOrReplace(environment.getPropertySources(), map);
}
private void addOrReplace(MutablePropertySources propertySources, Map<String, Object> map) {
MapPropertySource target = new MapPropertySource("applicationConfig: [consulKVs]", map);
if (propertySources.contains(PROPERTY_SOURCE_NAME)) {
PropertySource<?> applicationConfigurationPropertySources = propertySources.get(PROPERTY_SOURCE_NAME);
for(EnumerableCompositePropertySource applicationPropertySource : (ArrayList<EnumerableCompositePropertySource>)applicationConfigurationPropertySources.getSource()){
if(applicationPropertySource.getName() != null
&& applicationPropertySource.getName().contains("applicationConfig: [profile=")) {
for(PropertySource singleApplicationPropertySource : applicationPropertySource.getSource()){
if(singleApplicationPropertySource.getName().contains("applicationConfig: [classpath:/application")){
for (String key : map.keySet()) {
if (singleApplicationPropertySource.containsProperty(key)) {
((Properties) singleApplicationPropertySource.getSource())
.setProperty(key, (String) map.get(key));
} else {
((Properties) singleApplicationPropertySource.getSource()).put(key,
map.get(key));
}
}
applicationPropertySource.add(target);
Properties properties = new Properties();
properties.putAll(map);
propertySources.addLast(new PropertiesPropertySource("consulKVs", properties));
break;
}
}
break;
}
}
}
}
}
看起來您正在嘗試更改 spring 不適合的約定。 您提供的代碼不容易維護,需要深入了解 Spring 內部結構。 坦率地說,如果不調試如何實現您想要的,我無法判斷,但是我有另一種方法:
您可以通過以下方式使用 spring 配置文件:
假設您在application.properties
中有一個屬性db.name=abc
,在 consul 中有一個屬性 db.name db.name=xyz
,我假設您的目標是讓 spring 解析db.name=xyz
。
在這種情況下,將db.name=abc
移動到application-local.properties
並使用--spring.profiles.active=local
啟動應用程序,如果你想從本地文件中獲得屬性,如果你想沒有這個配置文件go 與領事。
您甚至可以在EnvironmentPostProcessor
中動態添加一個活動配置文件(無論如何您已經到了那里),但這是 EnvironmentPostProcessor 中的一行代碼。
您的代碼存在問題,您使用以下代碼添加新的屬性源。 請注意,當您調用“addLast”時,通過此方法添加的屬性源優先級最低,並且永遠不會更新已經可用的屬性。
propertySources.addLast(new PropertiesPropertySource("consulKVs", properties));
您可以使用“addFirst”代替上面的添加屬性源,該屬性源應具有最高優先級,如下面的代碼所示。 還有一些其他方法,例如“addAfter”和“addBefore”,您可以探索它們以在確切位置添加屬性源。 無論如何,“addFirst”將優先於所有其他方式,所以我認為您可以使用“addFirst”來更新屬性源。
propertySources.addFirst(new PropertiesPropertySource("consulKVs", properties));
我已經使用 ApplicationEnvironmentPreparedEvent 測試了這個場景,它工作正常。 希望它能解決您的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.