概述

在Spring Boot中,属性(Properties)是其提供的最强大的功能之一。这些属性可以从专用配置文件、环境变量等多个地方获取。因此,在调试时查找并记录特定属性有时很有用。本教程将介绍几种在Spring Boot应用中查找和日志化特定属性的方法。

创建测试应用

首先,我们创建一个简单的测试应用,后续我们将对其进行操作。

2. 创建测试应用

让我们创建一个带有三个自定义属性的应用模板。我们可以使用Spring Initializr来创建Spring Boot应用的起点,选择Java作为语言。其他选项,如Java版本、项目元数据等,可以根据需要自由选择。

接下来,我们在src/main/resources目录下添加一个新的application.properties文件:

app.name=MyApp
app.description=${app.name} is a Spring Boot application
bael.property=stagingValue

3. 使用上下文刷新事件日志属性

在Spring Boot应用中记录属性的三种方法之一是利用Spring事件,特别是org.springframework.context.event.ContextRefreshedEvent类和相应的EventListener。我们将展示如何记录所有可用属性,以及只打印来自特定文件的详细版本。

3.1. 日志所有属性

首先,创建一个bean和事件监听器方法:

@Component
public class AppContextRefreshedEventPropertiesPrinter {

    @EventListener
    public void handleContextRefreshed(ContextRefreshedEvent event) {
        // event handling logic
    }
}

我们使用@EventListener注解标记事件监听器方法。当ContextRefreshedEvent发生时,Spring会调用该方法。

下一步是从触发的事件中获取org.springframework.core.env.ConfigurableEnvironment接口的实例。ConfigurableEnvironment接口提供了一个有用的方法getPropertySources(),我们可以使用它获取所有属性源列表,例如环境、JVM或配置文件变量:

ConfigurableEnvironment env = (ConfigurableEnvironment) event.getApplicationContext().getEnvironment();

现在,让我们看看如何使用它打印所有属性,不仅来自application.properties文件,还包括环境、JVM变量等:

env.getPropertySources()
    .stream()
    .filter(ps -> ps instanceof MapPropertySource)
    .map(ps -> ((MapPropertySource) ps).getSource().keySet())
    .flatMap(Collection::stream)
    .distinct()
    .sorted()
    .forEach(key -> LOGGER.info("{}={}", key, env.getProperty(key)));

首先,我们从可用的属性源创建一个Stream。然后,使用filter()方法遍历org.springframework.core.env.MapPropertySource类型的属性源。

如名称所示,这种属性源中的属性存储在映射结构中。我们在下一步中使用流的map()方法获取属性键的集合。

接着,我们使用StreamflatMap()方法,因为我们想遍历单个属性键,而不是键集合,并且希望按字母顺序显示唯一的属性,不重复。

最后一步是记录属性键及其值。

启动应用后,我们应该能看到从各种来源获取的大量属性列表:

COMMAND_MODE=unix2003
CONSOLE_LOG_CHARSET=UTF-8
...
bael.property=defaultValue
app.name=MyApp
app.description=MyApp is a Spring Boot application
...
java.class.version=52.0
ava.runtime.name=OpenJDK Runtime Environment

3.2. 只日志application.properties文件中的属性

如果我们只想记录application.properties文件中的属性,几乎可以重用先前的所有代码。只需更改传递给filter()方法的lambda函数:

env.getPropertySources()
    .stream()
    .filter(ps -> ps instanceof MapPropertySource && ps.getName().contains("application.properties"))
    ...

现在,当我们启动应用时,应该看到如下日志:

bael.property=defaultValue
app.name=MyApp
app.description=MyApp is a Spring Boot application

4. 使用Environment接口日志属性

另一种记录属性的方法是使用org.springframework.core.env.Environment接口:

@Component
public class EnvironmentPropertiesPrinter {
    @Autowired
    private Environment env;

    @PostConstruct
    public void logApplicationProperties() {
        LOGGER.info("{}={}", "bael.property", env.getProperty("bael.property"));
        LOGGER.info("{}={}", "app.name", env.getProperty("app.name"));
        LOGGER.info("{}={}", "app.description", env.getProperty("app.description"));
    }
}

与使用上下文刷新事件的方法相比,唯一的限制是我们需要知道属性名才能获取其值。环境接口没有列出所有属性的方法。然而,这无疑是一种更短、更容易的技术。

启动应用后,我们应看到与之前相同的输出:

bael.property=defaultValue 
app.name=MyApp 
app.description=MyApp is a Spring Boot application

5. 使用Spring Actuator日志属性

Spring Actuator是一个非常有用的库,为应用提供了生产就绪的功能。**/env REST端点返回当前环境属性**。

首先,我们需要将Spring Actuator库添加到项目中:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>3.0.0</version>
</dependency>

接下来,我们需要启用/env端点,因为它默认是禁用的。打开application.properties,添加以下内容:

management.endpoints.web.exposure.include=env

现在,我们只需启动应用并访问/env端点。对于我们的应用,地址是http://localhost:8080/actuator/env。我们将看到一个包含所有环境变量(包括我们的属性)的大JSON:

{
  "activeProfiles": [],
  "propertySources": [
    ...
    {
      "name": "Config resource 'class path resource [application.properties]' via location 'optional:classpath:/' (document #0)",
      "properties": {
        "app.name": {
          "value": "MyApp",
          "origin": "class path resource [application.properties] - 10:10"
        },
        "app.description": {
          "value": "MyApp is a Spring Boot application",
          "origin": "class path resource [application.properties] - 11:17"
        },
        "bael.property": {
          "value": "defaultValue",
          "origin": "class path resource [application.properties] - 13:15"
        }
      }
    }
   ...
  ]
}

6. 总结

本文介绍了在Spring Boot应用中记录属性的方法。首先,我们创建了一个带有三个自定义属性的测试应用。然后,我们了解了三种不同的方法来检索和记录所需的属性。

如往常一样,文章的完整源代码可以在GitHub上找到。