概述
在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()
方法获取属性键的集合。
接着,我们使用Stream
的flatMap()
方法,因为我们想遍历单个属性键,而不是键集合,并且希望按字母顺序显示唯一的属性,不重复。
最后一步是记录属性键及其值。
启动应用后,我们应该能看到从各种来源获取的大量属性列表:
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上找到。