| 对于最新的稳定版本,请使用 Spring Boot 3.5.5! | 
使用注释处理器生成您自己的元数据
您可以轻松地从注释为@ConfigurationProperties通过使用spring-boot-configuration-processor罐。
jar 包括一个 Java 注释处理器,该处理器在编译项目时调用。
配置注释处理器
使用 Maven 构建时,配置编译器插件(3.12.0 或更高版本)以添加spring-boot-configuration-processor到注释处理器路径:
<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<annotationProcessorPaths>
						<path>
							<groupId>org.springframework.boot</groupId>
							<artifactId>spring-boot-configuration-processor</artifactId>
						</path>
					</annotationProcessorPaths>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>对于 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,您可以配置  | 
| 如果您在项目中使用 Lombok,则需要确保其注释处理器在 | 
自动元数据生成
处理器选取带有注释的类和方法@ConfigurationProperties.
| 使用 meta 注释的自定义注释 @ConfigurationProperties不支持。 | 
如果类具有单个参数化构造函数,则每个构造函数参数创建一个属性,除非构造函数使用@Autowired.
如果类具有显式注释的构造函数@ConstructorBinding,则为该构造函数的每个构造函数参数创建一个属性。
否则,通过标准 getter 和 setter 的存在来发现属性,这些 getter 和 setter 对集合和映射类型进行了特殊处理(即使仅存在 getter,也会检测到)。
注释处理器还支持使用@Data,@Value,@Getter和@Setter龙目岛注释。
请考虑以下示例:
- 
Java 
- 
Kotlin 
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;
	}
}import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties(prefix = "my.server")
class MyServerProperties(
	/**
	 * Name of the server.
	 */
	var name: String,
	/**
	 * IP address to listen to.
	 */
	var ip: String = "127.0.0.1",
	/**
	 * Port to listen to.
	 */
	var port: Int = 9797)这公开了三个属性,其中my.server.name没有默认值,并且my.server.ip和my.server.port默认为"127.0.0.1"和9797分别。
Javadoc on 字段用于填充description属性。
例如,描述my.server.ip是“要监听的 IP 地址”。
这description属性只有在类型可用作正在编译的源代码时才能填充。
当类型仅作为依赖项的编译类可用时,它不会被填充。
对于这种情况,应提供手动元数据。
| 您应该仅将纯文本与 @ConfigurationProperties字段 Javadoc,因为它们在添加到 JSON 之前不会被处理。 | 
如果您使用@ConfigurationProperties使用 record 类,则应通过类级 Javadoc 标签提供 Record 组件的描述@param(记录类中没有显式实例字段来放置常规字段级 Javadoc)。
注释处理器应用许多启发式方法从源模型中提取默认值。
只有当类型可用作正在编译的源代码时,才能提取默认值。
当类型仅作为依赖项的编译类可用时,它们将不会被提取。
此外,默认值必须静态提供。
特别是,不要引用在另一个类中定义的常量。
此外,注释处理器无法自动检测Collectionss.
对于无法检测到默认值的情况,应提供手动元数据。 请考虑以下示例:
- 
Java 
- 
Kotlin 
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
	}
}import org.springframework.boot.context.properties.ConfigurationProperties
import java.util.Arrays
@ConfigurationProperties(prefix = "my.messaging")
class MyMessagingProperties(
	val addresses: List<String> = ArrayList(Arrays.asList("a", "b")),
	var containerType: ContainerType = ContainerType.SIMPLE) {
	enum class ContainerType {
		SIMPLE, DIRECT
	}
}为了记录上述类中属性的默认值,您可以将以下内容添加到模块的手动元数据中:
{"properties": [
	{
		"name": "my.messaging.addresses",
		"defaultValue": ["a", "b"]
	},
	{
		"name": "my.messaging.container-type",
		"defaultValue": "simple"
	}
]}| 只有 name需要记录现有属性的其他元数据。 | 
嵌套属性
注释处理器会自动将内部类视为嵌套属性。
而不是记录ip和port在命名空间的根目录下,我们可以为其创建一个子命名空间。
考虑更新后的示例:
- 
Java 
- 
Kotlin 
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;
		}
	}
}import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties(prefix = "my.server")
class MyServerProperties(
	var name: String,
	var host: Host) {
	class Host(val ip: String, val port: Int = 0)
}前面的示例生成my.server.name,my.server.host.ip和my.server.host.port性能。
您可以使用@NestedConfigurationProperty字段或 getter 方法上的注释,以指示应将常规(非内部)类视为嵌套类。
| 这对集合和映射没有影响,因为这些类型会自动识别,并且会为每个类型生成一个元数据属性。 | 
添加其他元数据
Spring Boot 的配置文件处理非常灵活,通常存在未绑定到@ConfigurationProperties豆。
您可能还需要调整现有键的某些属性。
为了支持此类情况并让您提供自定义“提示”,注释处理器会自动合并来自META-INF/additional-spring-configuration-metadata.json到主元数据文件中。
如果引用已自动检测到的属性,则描述、默认值和弃用信息(如果已指定)将被覆盖。 如果在当前模块中未标识手动属性声明,则将其添加为新属性。
的格式additional-spring-configuration-metadata.json文件与常规文件完全相同spring-configuration-metadata.json.
附加属性文件是可选的。
如果没有任何其他属性,请不要添加该文件。