#spring-boot #properties #distributed
#spring-загрузка #свойства #распределенный
Вопрос:
Приведенный ниже пример кода взят из приложения Spring Boot, которое получает определения свойств из локального файла application.properties. Дополнительные или переопределяющие определения свойств получаются с удаленного сервера Consul. Цель состоит в том, чтобы приложение перечисляло все определения свойств независимо от источника. Пример настройки:
Локальный файл application.properties содержит это определение свойства spring.cloud.stream.bindings.breakoutOutputChannel.destination=breakout_topic_local
Переопределяющим определением для того же свойства на сервере Consul является: spring.cloud.stream.bindings.breakoutOutputChannel.destination=breakout_topic_production
В том же коде я использую два механизма для доступа к одному и тому же значению свойства. Первое — это использование аннотации @Value, второе — запрос свойств, полученных из среды. Способы получения свойств окружающей среды приложений также показаны ниже.
При использовании аннотации @Value получается правильное переопределяющее значение. Но при непосредственном доступе к определению свойства доступно только значение из локального файла. Пример показан ниже.
Возможно ли получить ту же карту свойств, что и в аннотации @Value, чтобы можно было перечислять ее содержимое?
Пример кода:
@Value("${spring.cloud.stream.bindings.breakoutOutputChannel.destination}")
String breakout;
@EventListener
public void onApplicationEvent(ApplicationReadyEvent event) {
Properties props =applicationProperties(event.getApplicationContext().getEnvironment());
log.info("Property spring.cloud.stream.bindings.breakoutOutputChannel.destination");
log.info( " value from bound var = " breakout);
log.info( " value from properties = " props.getProperty("spring.cloud.stream.bindings.breakoutOutputChannel.destination"));
}
public Properties applicationProperties(Environment env) {
final Properties properties = new Properties();
for(Iterator it = ((AbstractEnvironment) env).getPropertySources().iterator(); it.hasNext(); ) {
PropertySource propertySource = (PropertySource) it.next();
if (propertySource instanceof PropertiesPropertySource) {
log.info("Adding all properties contained in " propertySource.getName());
properties.putAll(((MapPropertySource) propertySource).getSource());
}
if (propertySource instanceof CompositePropertySource){
properties.putAll(getPropertiesInCompositePropertySource((CompositePropertySource) propertySource));
}
}
return properties;
}
private Properties getPropertiesInCompositePropertySource(CompositePropertySource compositePropertySource){
final Properties properties = new Properties();
compositePropertySource.getPropertySources().forEach(propertySource -> {
if (propertySource instanceof MapPropertySource) {
log.info("Adding all properties contained in " propertySource.getName());
properties.putAll(((MapPropertySource) propertySource).getSource());
}
if (propertySource instanceof CompositePropertySource)
properties.putAll(getPropertiesInCompositePropertySource((CompositePropertySource) propertySource));
});
return properties;
}
Пример вывода
Adding all properties contained in applicationConfig: [file:./application.properties]
Adding all properties contained in applicationConfig: [classpath:/application.properties]
Property spring.cloud.stream.bindings.breakoutOutputChannel.destination
value from bound var = breakout_topic_production
value from properties = breakout_topic_local
Ответ №1:
Хотя источником сгенерированного объекта properties, созданного в приведенном выше примере, является среда приложения, значения действительно являются только теми, которые включены в локальные файлы определения свойств.
Однако, если ключ свойства используется для получения значения непосредственно из среды, возвращаемое значение будет содержать любое переопределение, переданное приложению из Consul. Из примера возвращаемое значение из
event.getApplicationContext().getEnvironment().getProperty("spring.cloud.stream.bindings.breakoutOutputChannel.destination"));
вернет правильное значение свойства.