使用注解处理器生成您自己的元数据
您可以使用 `spring-boot-configuration-processor` jar 轻松地从使用 `@ConfigurationProperties` 注解的项生成您自己的配置元数据文件。该 jar 包含一个 Java 注解处理器,该处理器在编译项目时调用。
配置注解处理器
要使用该处理器,请包含对 `spring-boot-configuration-processor` 的依赖项。
在 Maven 中,依赖项应声明为可选的,如下例所示
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
在 Gradle 中,依赖项应在 `annotationProcessor` 配置中声明,如下例所示
dependencies {
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
}
如果您正在使用 `additional-spring-configuration-metadata.json` 文件,则应将 `compileJava` 任务配置为依赖于 `processResources` 任务,如下例所示
tasks.named('compileJava') {
inputs.files(tasks.named('processResources'))
}
此依赖关系确保在编译期间注解处理器运行时,其他元数据可用。
如果您在项目中使用 AspectJ,则需要确保注解处理器只运行一次。有几种方法可以做到这一点。在 Maven 中,您可以显式配置 `maven-apt-plugin` 并且只在那里添加对注解处理器的依赖。您也可以让 AspectJ 插件运行所有处理,并在 `maven-compiler-plugin` 配置中禁用注解处理,如下所示
|
如果您在项目中使用Lombok,则需要确保其注解处理器在 |
自动元数据生成
处理器会拾取用@ConfigurationProperties
注解的类和方法。
用@ConfigurationProperties 元注解的自定义注解不受支持。 |
如果类具有单个参数化构造函数,则除非构造函数用@Autowired
注解,否则会为每个构造函数参数创建一个属性。如果类具有用@ConstructorBinding
显式注解的构造函数,则为该构造函数的每个构造函数参数创建一个属性。否则,属性是通过标准 getter 和 setter 的存在来发现的,对集合和映射类型进行特殊处理(即使只存在 getter 也能检测到)。注解处理器还支持使用@Data
、@Value
、@Getter
和@Setter
Lombok 注解。
考虑以下示例
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my.server")
public class MyServerProperties {
/**
* Name of the server.
*/
private String name;
/**
* IP address to listen to.
*/
private String ip = "127.0.0.1";
/**
* Port to listener to.
*/
private int port = 9797;
// getters/setters ...
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getIp() {
return this.ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return this.port;
}
public void setPort(int port) {
this.port = port;
}
// fold:off
}
这将公开三个属性,其中my.server.name
没有默认值,my.server.ip
和my.server.port
分别默认为"127.0.0.1"
和9797
。字段上的Javadoc用于填充description
属性。例如,my.server.ip
的描述是“要监听的IP地址”。
您应该只对@ConfigurationProperties 字段Javadoc使用纯文本,因为它们在添加到JSON之前不会被处理。 |
如果您将@ConfigurationProperties
与记录类一起使用,则应通过类级Javadoc标签@param
提供记录组件的描述(记录类中没有显式实例字段可用于放置常规字段级Javadoc)。
注解处理器应用许多启发式方法来从源模型中提取默认值。必须静态提供默认值。特别是,不要引用在另一个类中定义的常量。此外,注解处理器无法自动检测Enum
和Collections
的默认值。
对于无法检测到默认值的情况,应提供手动元数据。考虑以下示例
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my.messaging")
public class MyMessagingProperties {
private List<String> addresses = new ArrayList<>(Arrays.asList("a", "b"));
private ContainerType containerType = ContainerType.SIMPLE;
// getters/setters ...
public List<String> getAddresses() {
return this.addresses;
}
public void setAddresses(List<String> addresses) {
this.addresses = addresses;
}
public ContainerType getContainerType() {
return this.containerType;
}
public void setContainerType(ContainerType containerType) {
this.containerType = containerType;
}
public enum ContainerType {
SIMPLE, DIRECT
}
}
为了记录上面类中属性的默认值,您可以将以下内容添加到模块的手动元数据
{"properties": [
{
"name": "my.messaging.addresses",
"defaultValue": ["a", "b"]
},
{
"name": "my.messaging.container-type",
"defaultValue": "simple"
}
]}
只需要属性的name 即可为现有属性记录其他元数据。 |
嵌套属性
注解处理器会自动将内部类视为嵌套属性。与其在命名空间的根目录记录ip
和port
,不如为其创建一个子命名空间。考虑更新后的示例
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my.server")
public class MyServerProperties {
private String name;
private Host host;
// getters/setters ...
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Host getHost() {
return this.host;
}
public void setHost(Host host) {
this.host = host;
}
public static class Host {
private String ip;
private int port;
// getters/setters ...
public String getIp() {
return this.ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return this.port;
}
public void setPort(int port) {
this.port = port;
}
// @fold:off // getters/setters ...
}
}
前面的示例会为my.server.name
、my.server.host.ip
和my.server.host.port
属性生成元数据信息。您可以对字段使用@NestedConfigurationProperty
注解来指示应将常规(非内部)类视为嵌套类。
这对集合和映射没有影响,因为这些类型会自动识别,并且会为每个类型生成单个元数据属性。 |
添加附加元数据
Spring Boot 的配置文件处理非常灵活,通常情况下可能存在一些属性没有绑定到@ConfigurationProperties
bean。您可能还需要调整现有密钥的一些属性。为了支持这种情况并允许您提供自定义“提示”,注解处理器会自动将META-INF/additional-spring-configuration-metadata.json
中的项目合并到主元数据文件中。
如果您引用一个已自动检测到的属性,则如果指定了描述、默认值和弃用信息,则会覆盖它们。如果在当前模块中未识别手动属性声明,则将其添加为新属性。
additional-spring-configuration-metadata.json
文件的格式与常规spring-configuration-metadata.json
完全相同。附加属性文件是可选的。如果您没有任何其他属性,请不要添加该文件。