使用註解處理器生成您自己的元資料

您可以使用 spring-boot-configuration-processor jar 包輕鬆地從帶有 @ConfigurationProperties 註解的項中生成您自己的配置元資料檔案。該 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,您可以顯式配置 maven-apt-plugin 並僅在此處新增對註解處理器的依賴。您還可以讓 AspectJ 外掛執行所有處理,並停用 maven-compiler-plugin 配置中的註解處理,如下所示

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-compiler-plugin</artifactId>
	<configuration>
		<proc>none</proc>
	</configuration>
</plugin>

如果您在專案中使用 Lombok,則需要確保其註解處理器在 spring-boot-configuration-processor 之前執行。為此,使用 Maven 時,透過 Maven 編譯器外掛的 annotationProcessors 屬性以所需的順序列出註解處理器。使用 Gradle 時,在 annotationProcessor 配置中以所需的順序宣告依賴項。

自動元資料生成

處理器會拾取帶有 @ConfigurationProperties 註解的類和方法。它還會拾取帶有 @ConfigurationPropertiesSource 註解的類

不支援使用上述任一註解進行元註解的自定義註解。

如果類只有一個帶引數的建構函式,則會為每個建構函式引數建立一個屬性,除非該建構函式使用 @Autowired 註解。如果類有一個顯式使用 @ConstructorBinding 註解的建構函式,則會為該建構函式的每個建構函式引數建立一個屬性。否則,屬性透過標準 getter 和 setter 的存在來發現,並對集合和對映型別進行特殊處理(即使只存在 getter 也會被檢測到)。註解處理器還支援使用 @Data@Value@Getter@Setter lombok 註解。

考慮以下示例

  • Java

  • Kotlin

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("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("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.ipmy.server.port 預設值分別為 "127.0.0.1"9797。欄位上的 Javadoc 用於填充 description 屬性。例如,my.server.ip 的描述是“要監聽的 IP 地址。”。

description 屬性只能在型別作為正在編譯的原始碼可用時填充。當型別僅作為依賴項中的已編譯類可用時,它不會被填充。對於此類情況,您可以 提供源元資料提供手動條目

您應該只在 @ConfigurationProperties 欄位 Javadoc 中使用純文字,因為它們在新增到 JSON 之前不會被處理。

如果您將 @ConfigurationProperties 與記錄類一起使用,則記錄元件的描述應透過類級別 Javadoc 標籤 @param 提供(記錄類中沒有顯式的例項欄位可以放置常規的欄位級別 Javadoc)。

註解處理器應用了一些啟發式方法從源模型中提取預設值。預設值只能在型別作為正在編譯的原始碼可用時提取。當型別僅作為依賴項中的已編譯類可用時,它們不會被提取。此外,預設值必須靜態提供。特別是,不要引用在另一個類中定義的常量。此外,註解處理器無法自動檢測 Collections 的預設值。

對於無法檢測到預設值的情況,應提供 手動元資料。請考慮以下示例

  • Java

  • Kotlin

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("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("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 來記錄現有屬性的附加元資料。

巢狀屬性

註解處理器會自動將內部類視為巢狀屬性。與其在名稱空間的根部記錄 ipport,我們可以為其建立一個子名稱空間。考慮更新的示例

  • Java

  • Kotlin

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("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("my.server")
class MyServerProperties(
	var name: String,
	var host: Host) {

	class Host(val ip: String, val port: Int = 0)

}

前面的示例為 my.server.namemy.server.host.ipmy.server.host.port 屬性生成元資料資訊。您可以使用欄位或 getter 方法上的 @NestedConfigurationProperty 註解來指示常規(非內部)類應被視為巢狀類。

這對集合和對映沒有影響,因為這些型別會自動識別,併為它們中的每一個生成一個元資料屬性。

配置屬性源

如果另一個模組中的型別在 @ConfigurationProperties 註解型別中使用,則某些元資料元素無法自動發現。重用上面的示例,如果 Host 位於另一個模組中,則完整的元資料不可用,因為註解處理器無法訪問 Host 的原始碼。

為了處理此用例,請在包含 Host 型別的模組中添加註解處理器,並使用 @ConfigurationPropertiesSource 註解它

  • Java

  • Kotlin

import org.springframework.boot.context.properties.ConfigurationPropertiesSource;

@ConfigurationPropertiesSource
public class Host {

	/**
	 * IP address to listen to.
	 */
	private String ip = "127.0.0.1";

	/**
	 * Port to listener to.
	 */
	private int port = 9797;

	// 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.ConfigurationPropertiesScan

@ConfigurationPropertiesScan
class Host {

	/**
	 * IP address to listen to.
	 */
	var ip: String = "127.0.0.1"

	/**
	 * Port to listener to.
	 */
	var port = 9797

}

這會在 META-INF/spring/configuration-metadata/com.example.Host.json 中為 Host 生成元資料,並在註解處理器處理此類型別時自動重用。

您還可以註解位於另一個模組中的父類,@ConfigurationProperties 註解型別從該父類擴充套件而來。

如果您需要重用您無法控制的型別的元資料,請建立一個具有上述模式的檔案,只要它在類路徑上可用,就會被使用。

新增附加元資料

Spring Boot 的配置檔案處理非常靈活,通常情況下可能存在未繫結到 @ConfigurationProperties bean 的屬性。您可能還需要調整現有鍵的某些屬性或完全忽略該鍵。為了支援這些情況並允許您提供自定義“提示”,註解處理器會自動將 META-INF/additional-spring-configuration-metadata.json 中的項合併到主元資料檔案中。

為型別生成源元資料時,您還可以為該型別(例如 com.example.SomeType)在 META-INF/spring/configuration/metadata/com.example.SomeType.json 中建立自定義元資料。

如果您引用已自動檢測到的屬性,則其描述、預設值和棄用資訊(如果指定)將被覆蓋。如果手動屬性宣告在當前模組中未識別,則將其新增為新屬性。

附加元資料檔案的格式與常規的 spring-configuration-metadata.json 完全相同。“ignored.properties”部分中包含的項將從生成的 spring-configuration-metadata.json 檔案的“properties”部分中刪除。

附加屬性檔案是可選的。如果您沒有任何附加屬性,請不要新增該檔案。

© . This site is unofficial and not affiliated with VMware.