Как зарегистрировать активную конфигурацию в приложении Spring Boot?
Мне бы очень хотелось использовать конфигурацию YAML для Spring Boot, так как я считаю ее вполне читаемой и полезной для того, чтобы иметь один файл, показывающий, какие свойства активны в моих разных профилях. К сожалению, я обнаружил, что параметры настройки в application.yml
могут быть довольно хрупкими.
Такие вещи, как использование вкладки вместо пробелов, не приведут к тому, что свойства не будут существовать (без предупреждений, насколько я могу видеть), и слишком часто я обнаруживаю, что мои активные профили не установлены из-за неизвестной проблемы с моим YAML.
Итак, мне было интересно, есть ли какие-либо перехватчики, которые позволят мне получить активные профили и свойства в настоящее время, чтобы я мог их записывать.
Точно так же существует ли способ заставить start-up сбой, если application.yml
содержит ошибки? Либо это, либо средство для проверки подлинности YAML, чтобы я мог убить процесс запуска.
Ответы
Ответ 1
У меня была такая же проблема, и я хотел бы, чтобы был флаг отладки, который бы сообщал системе обработки профилей, чтобы выплеснуть некоторые полезные протоколирования. Один из возможных способов сделать это - зарегистрировать прослушиватель событий для контекста вашего приложения и распечатать профили из среды. Я не пробовал делать это так, поэтому ваш пробег может измениться. Я думаю, может быть, что-то вроде того, что описано здесь:
Как добавить привязку к событию инициализации контекста приложения?
Тогда вы сделаете что-то подобное в своем слушателе:
System.out.println("Active profiles: " + Arrays.toString(ctxt.getEnvironment().getActiveProfiles()));
Возможно, стоит попробовать. Другой способ, которым вы, вероятно, могли бы сделать это, - объявить среду, которую нужно ввести в код, где вам нужно распечатать профили. То есть:.
@Component
public class SomeClass {
@Autowired
private Environment env;
...
private void dumpProfiles() {
// Print whatever needed from env here
}
}
Ответ 2
Оператор Actuator/env отображает свойства, но не показывает, какое значение свойства действительно активно. Очень часто вы можете переопределить свои свойства приложения с помощью
- свойства приложения для профиля
- аргументы командной строки
- Переменные среды ОС
Таким образом, у вас будет одно и то же свойство и разные значения в нескольких источниках.
Снимок ниже печатает значения активных свойств приложения при запуске:
@Configuration
public class PropertiesLogger {
private static final Logger log = LoggerFactory.getLogger(PropertiesLogger.class);
@Autowired
private AbstractEnvironment environment;
@PostConstruct
public void printProperties() {
log.info("**** APPLICATION PROPERTIES SOURCES ****");
Set<String> properties = new TreeSet<>();
for (PropertiesPropertySource p : findPropertiesPropertySources()) {
log.info(p.toString());
properties.addAll(Arrays.asList(p.getPropertyNames()));
}
log.info("**** APPLICATION PROPERTIES VALUES ****");
print(properties);
}
private List<PropertiesPropertySource> findPropertiesPropertySources() {
List<PropertiesPropertySource> propertiesPropertySources = new LinkedList<>();
for (PropertySource<?> propertySource : environment.getPropertySources()) {
if (propertySource instanceof PropertiesPropertySource) {
propertiesPropertySources.add((PropertiesPropertySource) propertySource);
}
}
return propertiesPropertySources;
}
private void print(Set<String> properties) {
for (String propertyName : properties) {
log.info("{}={}", propertyName, environment.getProperty(propertyName));
}
}
}
Ответ 3
Если application.yml
содержит ошибки, это приведет к сбою при запуске. Я думаю, это зависит от того, что вы подразумеваете под "ошибкой". Конечно, он не сработает, если YAML не сформирован. Также, если вы устанавливаете @ConfigurationProperties
, которые помечены как ignoreInvalidFields=true
, например, или если вы устанавливаете значение, которое невозможно преобразовать. Это довольно широкий диапазон ошибок.
Активные профили, вероятно, будут регистрироваться при запуске с помощью реализации Environment
(но в любом случае вам легко взять это и записать в свой код запуска - toString()
of the Environment
будет отображать список активные профили, я думаю). Активные профили (и более) также доступны в конечной точке /env, если вы добавляете Actuator.
Ответ 4
Если вы хотите получить активные профили перед инициализацией приложения beans/, единственный способ, которым я нашел, - это зарегистрировать собственный баннер в SpringApplication/Builder.
Ответ 5
В дополнение к другим ответам: ведение активных свойств при обновлении контекста.
Java 8
package mypackage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Slf4j
@Component
public class AppContextEventListener {
@EventListener
public void handleContextRefreshed(ContextRefreshedEvent event) {
printActiveProperties((ConfigurableEnvironment) event.getApplicationContext().getEnvironment());
}
private void printActiveProperties(ConfigurableEnvironment env) {
System.out.println("************************* ACTIVE APP PROPERTIES ******************************");
List<MapPropertySource> propertySources = new ArrayList<>();
env.getPropertySources().forEach(it -> {
if (it instanceof MapPropertySource && it.getName().contains("applicationConfig")) {
propertySources.add((MapPropertySource) it);
}
});
propertySources.stream()
.map(propertySource -> propertySource.getSource().keySet())
.flatMap(Collection::stream)
.distinct()
.sorted()
.forEach(key -> {
try {
System.out.println(key + "=" + env.getProperty(key));
} catch (Exception e) {
log.warn("{} -> {}", key, e.getMessage());
}
});
System.out.println("******************************************************************************");
}
}
котлинский
package mypackage
import mu.KLogging
import org.springframework.context.event.ContextRefreshedEvent
import org.springframework.context.event.EventListener
import org.springframework.core.env.ConfigurableEnvironment
import org.springframework.core.env.MapPropertySource
import org.springframework.stereotype.Component
@Component
class AppContextEventListener {
companion object : KLogging()
@EventListener
fun handleContextRefreshed(event: ContextRefreshedEvent) {
printActiveProperties(event.applicationContext.environment as ConfigurableEnvironment)
}
fun printActiveProperties(env: ConfigurableEnvironment) {
println("************************* ACTIVE APP PROPERTIES ******************************")
env.propertySources
.filter { it is MapPropertySource }
.map { it as MapPropertySource }
.filter { it.name.contains("applicationConfig") }
.map { it -> it.source.keys }
.flatMap { it }
.distinctBy { it }
.sortedBy { it }
.forEach { it ->
try {
println("$it=${env.getProperty(it)}")
} catch (e: Exception) {
logger.warn("$it -> ${e.message}")
}
}
println("******************************************************************************")
}
}
Вывод:
************************* ACTIVE APP PROPERTIES ******************************
server.port=3000
spring.application.name=my-app
...
2017-12-29 13:13:32.843 WARN 36252 --- [ main] m.AppContextEventListener : spring.boot.admin.client.service-url -> Could not resolve placeholder 'management.address' in value "http://${management.address}:${server.port}"
...
spring.datasource.password=
spring.datasource.url=jdbc:postgresql://localhost/my_db?currentSchema=public
spring.datasource.username=db_user
...
******************************************************************************