1. Overview
1.概述
When writing a Spring Boot application, it’s helpful to map configuration properties onto Java beans. What’s the best way to document these properties, though?
在编写 Spring Boot 应用程序时,将配置属性映射到 Java Bean 上是非常有用的。但是,记录这些属性的最佳方式是什么?
In this tutorial, we’ll explore the Spring Boot Configuration Processor and the associated JSON metadata files that document each property’s meaning, constraints, and so on.
在本教程中,我们将探讨Spring Boot配置处理器和相关的JSON元数据文件,这些文件记录了每个属性的含义、约束等。
2. Configuration Metadata
2.配置元数据
Most of the applications we work on as developers must be configurable to some extent. However, usually, we don’t really understand what a configuration parameter does, if it has a default value, if it’s deprecated, and at times, we don’t even know the property exists.
作为开发人员,我们工作的大多数应用程序在某种程度上必须是可配置的。然而,通常情况下,我们并不真正了解一个配置参数的作用,它是否有一个默认值,是否被废弃,有时,我们甚至不知道这个属性的存在。
To help us out, Spring Boot generates configuration metadata in a JSON file, which gives us useful information on how to use the properties. So, the configuration metadata is a descriptive file which contains the necessary information for interaction with the configuration properties.
为了帮助我们,Spring Boot在JSON文件中生成了配置元数据,它为我们提供了如何使用属性的有用信息。因此,配置元数据是一个描述性文件,其中包含与配置属性互动的必要信息。
The really nice thing about this file is that IDEs can read it, too, giving us autocomplete of Spring properties, as well as other configuration hints.
这个文件真正的好处是,IDE也可以读取它,为我们提供Spring属性的自动完成,以及其他配置提示。
3. Dependencies
3.依赖性
In order to generate this configuration metadata, we’ll use the configuration processor from the spring-boot-configuration-processor dependency.
为了生成这个配置元数据,我们将使用来自spring-boot-configuration-processor依赖性的配置处理器。
So, let’s go ahead and add the dependency as optional:
因此,让我们继续前进,将依赖关系添加为optional。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.1.6.RELEASE</version>
<optional>true</optional>
</dependency>
This dependency will provide us with a Java annotation processor invoked when we build our project. We’ll talk in detail about this later on.
这个依赖关系将为我们提供一个在我们构建项目时调用的Java注释处理器。我们将在后面详细讨论这个问题。
It’s a best practice to add a dependency as optional in Maven in order to prevent @ConfigurationProperties from being applied to other modules that our project uses.
在Maven中把依赖关系添加为optional是一种最佳做法,以防止@ConfigurationProperties被应用于我们项目使用的其他模块。
4. Configuration Properties Example
4.配置属性示例
To see the processor in action, let’s imagine we have a few properties that we need to include in our Spring Boot application via a Java bean:
为了了解处理器的运行情况,让我们想象一下,我们有几个属性需要通过一个Java Bean包含在我们的Spring Boot应用程序中。
@Configuration
@ConfigurationProperties(prefix = "database")
public class DatabaseProperties {
public static class Server {
private String ip;
private int port;
// standard getters and setters
}
private String username;
private String password;
private Server server;
// standard getters and setters
}
To do this, we’d use the @ConfigurationProperties annotation. The configuration processor scans for classes and methods with this annotation to access the configuration parameters and generate configuration metadata.
要做到这一点,我们要使用@ConfigurationProperties注解。配置处理器会扫描带有该注解的类和方法,以访问配置参数并生成配置元数据。
Let’s add a couple of these properties into a properties file. In this case, we’ll call it databaseproperties-test.properties:
让我们把这些属性中的几个添加到一个属性文件中。在这种情况下,我们将称之为databaseproperties-test.properties。
#Simple Properties
database.username=baeldung
database.password=password
And, just to be sure, we’ll also add a test to make sure that we are all lined up:
而且,为了确定,我们还将添加一个测试,以确保我们都排好了队。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AnnotationProcessorApplication.class)
@TestPropertySource("classpath:databaseproperties-test.properties")
public class DatabasePropertiesIntegrationTest {
@Autowired
private DatabaseProperties databaseProperties;
@Test
public void whenSimplePropertyQueriedThenReturnsPropertyValue()
throws Exception {
Assert.assertEquals("Incorrectly bound Username property",
"baeldung", databaseProperties.getUsername());
Assert.assertEquals("Incorrectly bound Password property",
"password", databaseProperties.getPassword());
}
}
We’ve also added the nested properties database.server.id and database.server.port via the inner class Server. We should add the inner class Server as well as a field server with its own getter and setter.
我们还通过内类Server添加了嵌套属性database.server.id和database.server.port。我们应该添加内类Server以及一个字段server,有自己的getter和setter。
In our test, let’s do a quick check to make sure we can set and read successfully nested properties as well:
在我们的测试中,让我们做一个快速检查,以确保我们也能成功地设置和读取嵌套属性。
@Test
public void whenNestedPropertyQueriedThenReturnsPropertyValue()
throws Exception {
Assert.assertEquals("Incorrectly bound Server IP nested property",
"127.0.0.1", databaseProperties.getServer().getIp());
Assert.assertEquals("Incorrectly bound Server Port nested property",
3306, databaseProperties.getServer().getPort());
}
Okay, now we’re ready to use the processor.
好了,现在我们准备使用处理器了。
5. Generating Configuration Metadata
5.生成配置元数据
We mentioned earlier that the configuration processor generates a file – it does this uses annotation processing.
我们在前面提到,配置处理器会生成一个文件–它这样做是使用注释处理。
So, after compiling our project, we’ll see a file called spring-configuration-metadata.json inside target/classes/META-INF:
因此,在编译我们的项目后,我们将看到一个名为spring-configuration-metadata.json的文件在target/classes/META-INF:。
{
"groups": [
{
"name": "database",
"type": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties"
},
{
"name": "database.server",
"type": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties$Server",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties",
"sourceMethod": "getServer()"
}
],
"properties": [
{
"name": "database.password",
"type": "java.lang.String",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties"
},
{
"name": "database.server.ip",
"type": "java.lang.String",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties$Server"
},
{
"name": "database.server.port",
"type": "java.lang.Integer",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties$Server",
"defaultValue": 0
},
{
"name": "database.username",
"type": "java.lang.String",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties"
}
],
"hints": []
}
Next, let’s see how changing annotations on our Java beans affect the metadata.
接下来,让我们看看在我们的Java Bean上改变注解是如何影响元数据的。
5.1. Additional Information on Configuration Metadata
5.1.关于配置元数据的其他信息
First, let’s add JavaDoc comments on Server.
首先,让我们在Server上添加JavaDoc注释。
Second, let’s give a default value to the database.server.port field and finally add the @Min and @Max annotations:
其次,让我们给database.server.port字段一个默认值,最后添加@Min和@Max注释。
public static class Server {
/**
* The IP of the database server
*/
private String ip;
/**
* The Port of the database server.
* The Default value is 443.
* The allowed values are in the range 400-4000.
*/
@Min(400)
@Max(800)
private int port = 443;
// standard getters and setters
}
If we check the spring-configuration-metadata.json file now, we’ll see this extra information reflected:
如果我们现在检查spring-configuration-metadata.json文件,我们会看到这个额外的信息反映出来。
{
"groups": [
{
"name": "database",
"type": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties"
},
{
"name": "database.server",
"type": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties$Server",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties",
"sourceMethod": "getServer()"
}
],
"properties": [
{
"name": "database.password",
"type": "java.lang.String",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties"
},
{
"name": "database.server.ip",
"type": "java.lang.String",
"description": "The IP of the database server",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties$Server"
},
{
"name": "database.server.port",
"type": "java.lang.Integer",
"description": "The Port of the database server. The Default value is 443.
The allowed values are in the range 400-4000",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties$Server",
"defaultValue": 443
},
{
"name": "database.username",
"type": "java.lang.String",
"sourceType": "com.baeldung.autoconfiguration.annotationprocessor.DatabaseProperties"
}
],
"hints": []
}
We can check the differences with the database.server.ip and database.server.port fields. Indeed, the extra information is quite helpful. As a result, it’s much easier for developers and IDEs to understand what each property does.
我们可以通过database.server.ip和database.server.port字段检查差异。事实上,这些额外的信息是很有帮助的。因此,对于开发者和IDE来说,更容易理解每个属性的作用。
We should also make sure we trigger the build to get the updated file. In Eclipse, if we check the Build Automatically option, each save action will trigger a build. In IntelliJ, we should trigger the build manually.
我们还应该确保触发构建以获得更新的文件。在Eclipse中,如果我们勾选了Build Automatically选项,每次保存动作都会触发构建。在 IntelliJ 中,我们应该手动触发构建。
5.2. Understanding the Metadata Format
5.2.了解元数据格式
Let’s have a closer look at the JSON metadata file and discuss its components.
让我们仔细看看JSON元数据文件并讨论其组成部分。
Groups are higher-level items used to group other properties, without specifying a value itself. In our example, we have the database group, which is also the prefix of the configuration properties. We also have a server group, which we created via an inner class and groups ip and port properties.
组是更高层次的项目,用于对其他属性进行分组,本身并不指定一个值。在我们的例子中,我们有database组,它也是配置属性的前缀。我们还有一个server组,我们通过一个内部类来创建,并将ip和port属性分组。
Properties are configuration items for which we can specify a value. These properties are set in .properties or .yml files and can have extra information, like default values and validations, as we saw in the example above.
属性是我们可以指定一个值的配置项。这些属性在.properties或.yml文件中设置,可以有额外的信息,如默认值和验证,正如我们在上面的例子中看到的那样。
Hints are additional information to help the user set the property value. For example, if we have a set of allowed value for a property, we can provide a description of what each of them does. The IDE will provide auto-competition help for these hints.
提示是帮助用户设置属性值的额外信息。例如,如果我们有一组属性的允许值,我们可以提供每个属性的作用描述。IDE将为这些提示提供自动竞争帮助。
Each component on the configuration metadata has its own attributes to explain in finer details the configuration properties.
配置元数据上的每个组件都有自己的属性,以更详细地解释配置属性。
6. Conclusion
6.结论
In this article, we looked at the Spring Boot Configuration Processor and its ability to create configuration metadata. Using this metadata makes it a lot easier to interact with our configuration parameters.
在这篇文章中,我们研究了Spring Boot配置处理器及其创建配置元数据的能力。使用这种元数据使我们与配置参数的交互变得更加容易。
We gave an example of a generated configuration metadata and explained in details its format and components.
我们给出了一个生成配置元数据的例子,并详细解释了其格式和组成部分。
We also saw how helpful the autocomplete support on our IDE can be.
我们也看到了我们的IDE上的自动完成支持是多么的有用。
As always, all of the code snippets mentioned in this article can be found on our GitHub repository.
一如既往,本文中提到的所有代码片段都可以在我们的GitHub仓库中找到。