如何在Spring Boot应用程序中记录活动配置?

2022-09-01 02:02:00

我真的很想将YAML配置用于Spring Boot,因为我发现有一个文件显示哪些属性在我的不同配置文件中处于活动状态,这是非常可读和有用的。不幸的是,我发现设置属性可能相当脆弱。application.yml

使用制表符而不是空格之类的事情将导致属性不存在(据我所知没有警告),并且由于我的YAML的一些未知问题,我经常发现我的活动配置文件未被设置。

因此,我想知道是否有任何钩子可以使我掌握当前活动的配置文件和属性,以便我可以记录它们。

同样,如果有方法导致启动失败,如果包含错误?要么是这样,要么是我自己验证YAML的一种方式,这样我就可以扼杀启动过程。application.yml


答案 1

除了其他答案之外:在上下文刷新事件上记录活动属性。

爪哇 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.name.contains("applicationConfig") }
                .map { it as EnumerablePropertySource<*> }
                .map { it -> it.propertyNames.toList() }
                .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
...
******************************************************************************

答案 2

我遇到了同样的问题,并希望有一个调试标志,可以告诉配置文件处理系统吐出一些有用的日志记录。执行此操作的一种可能方法是为应用程序上下文注册事件侦听器,并从环境中打印出配置文件。我自己没有尝试过这样做,所以你的里程可能会有所不同。我想也许像这里概述的那样:

如何在应用程序上下文初始化事件中添加钩子?

然后你会在你的听众中做这样的事情:

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
  }
}

推荐