跳到主要内容

11、Spring Boot 3.x 特性-配置元数据

Spring Boot jar包含元数据文件,提供所有支持的配置属性的详细信息。
这些文件让IDE开发人员在配置application.propertiesapplication.yml 时提供上下文帮助和“code completion”。

大部分元数据文件是在编译时通过处理所有带有@ConfigurationProperties注解的项自动生成的。然而,可以为极端用例或更高级的用例手工编写部分元数据。

一、元数据格式化

配置元数据文件位于META-INF/spring-configuration-metadata.json下的jar文件中。
它们使用JSON格式,项目分类在“groups”或“properties”下,附加值提示分类在“hints”下,如下所示:

{
   
     "groups": [
    {
   
     
        "name": "server",
        "type": "org.springframework.boot.autoconfigure.web.ServerProperties",
        "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
    },
    {
   
     
        "name": "spring.jpa.hibernate",
        "type": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties$Hibernate",
        "sourceType": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties",
        "sourceMethod": "getHibernate()"
    }
    ...
],"properties": [
    {
   
     
        "name": "server.port",
        "type": "java.lang.Integer",
        "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
    },
    {
   
     
        "name": "server.address",
        "type": "java.net.InetAddress",
        "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
    },
    {
   
     
          "name": "spring.jpa.hibernate.ddl-auto",
          "type": "java.lang.String",
          "description": "DDL mode. This is actually a shortcut for the \"hibernate.hbm2ddl.auto\" property.",
          "sourceType": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties$Hibernate"
    }
    ...
],"hints": [
    {
   
     
        "name": "spring.jpa.hibernate.ddl-auto",
        "values": [
            {
   
     
                "value": "none",
                "description": "Disable DDL handling."
            },
            {
   
     
                "value": "validate",
                "description": "Validate the schema, make no changes to the database."
            },
            {
   
     
                "value": "update",
                "description": "Update the schema if necessary."
            },
            {
   
     
                "value": "create",
                "description": "Create the schema and destroy previous data."
            },
            {
   
     
                "value": "create-drop",
                "description": "Create and then destroy the schema at the end of the session."
            }
        ]
    }
]}

每个“property”都是用户用给定值指定的配置项。例如,server.port和 server.address,可以在你的application.properties/application.yaml中指定。

server.port=9090
server.address=127.0.0.1

groups”是更高级别的项,它们本身不指定值,而是为属性提供上下文分组。例如server.port 和 server.address属性归属于 server组。并不是要求每个“property”都有一个“groups”。

最后,“hints”是用于帮助用户配置给定属性的附加信息。例如,当开发人员配置spring.jpa.hibernate.ddl-auto属性时,工具可以使用这些提示为nonevalidateupdatecreatecreate-drop值提供一些自动完成帮助。

二、元数据提示

为了改善用户体验并进一步帮助用户配置给定的属性,你可以提供额外的元数据:

1、 描述属性的潜在值列表;
2、 关联提供者,将定义良好的语义附加到属性,以便工具可以根据项目的上下文发现潜在值的列表;

Value 提示

每个提示的name属性引用一个属性的名称。在前面展示的初始示例中,我们为spring.jpa.hibernate.ddl-auto属性提供了5个值:nonevalidateupdatecreatecreate-drop。每个值也可以有一个描述。
如果属性的类型是Map,则可以为键和值提供提示(但不能为Map本身提供提示)。特殊的.keys.values后缀必须分别指向键和值。
假设一个my.contexts Map,将 String 映射成Integer,如下例子:

@ConfigurationProperties("my")
public class MyProperties {
   
     

    private Map<String, Integer> contexts;

    // getters/setters ...

}

假设Map中的keysample1sample2,为了为键提供额外的内容帮助,你可以将以下JSON添加到模块的手动元数据中(添加额外元数据):

{
   
     "hints": [
    {
   
     
        "name": "my.contexts.keys",
        "values": [
            {
   
     
                "value": "sample1"
            },
            {
   
     
                "value": "sample2"
            }
        ]
    }
]}

Value 提供程序

提供程序是将语义附加到属性的强大方法。在本节中,我们定义了官方的提供程序,你可以使用它们来进行自己的提示。但是,你最喜欢的IDE可能实现其中一些,也可能一个也不实现。
通俗一点就是属性配置值的来源。

Any

特殊的any provider值允许提供任何附加值。如果支持的话,应该应用基于属性类型的常规值验证。如果你有一个值列表,并且任何额外的值仍应视为有效,则通常使用此提供程序。
例如:

@ConfigurationProperties(prefix = "my.messaging")
public class MyMessagingProperties {
   
     

    /**
     * Addresses List
     */
    private List<String> addresses = new ArrayList<>(Arrays.asList("a", "b"));
    }

my.messaging.addresses 属性默认值列表是 “a”,“b”。如果输入其它值IDEA会提示如下。
 
如果允许其它任意值,那么可以在添加额外元数据提供程序。

"hints": [
    {
   
     
      "name": "my.messaging.addresses",
      "values": [
        {
   
     
          "value": "a"
        },
        {
   
     
          "value": "b"
        }
      ],
      "providers": [
        {
   
     
          "name": "any"
        }
      ]
    }]

 

Class Reference

class-reference提供程序自动完成项目中可用的类。

  "hints": [
    {
   
     
      "name": "server.servlet.jsp.class-name",
      "providers": [
        {
   
     
          "name": "class-reference",
          "parameters": {
   
     
            "target": "jakarta.servlet.http.HttpServlet"
          }
        }
      ]
    }

target:类的完全限定名
concrete: 指定是否只将具体类视为有效的候选类。默认true
 

Handle As

handle-as提供程序允许你将属性的类型替换为更高级的类型。当属性具有java.lang.String类型时,通常会发生这种情况,因为你不希望你的配置类依赖于可能不在类路径中的类。

 "hints": [
    {
   
     
      "name": "my.local",
      "providers": [
        {
   
     
          "name": "handle-as",
          "parameters": {
   
     
            "target": "org.springframework.core.io.Resource"
          }
        }
      ]
    }]

 
Handle As 支持的参数:

参数 类型 描述
target String (Class) java.lang.Enum java.nio.charset.Charset java.util.Locale org.springframework.util.MimeType org.springframework.core.io.Resource

Spring Bean Reference

spring-bean-reference提供程序自动完成在当前项目的配置中定义的bean。
下面的元数据片段对应于标准的spring.jmx.server属性,它定义了要使用的MBeanServer bean的名称:

{
   
     "hints": [
    {
   
     
        "name": "spring.jmx.server",
        "providers": [
            {
   
     
                "name": "spring-bean-reference",
                "parameters": {
   
     
                    "target": "javax.management.MBeanServer"
                }
            }
        ]
    }
]}

Spring Profile Name

Spring -profile-name提供程序自动完成在当前项目的配置中定义的Spring配置文件。下面的元数据片段对应于标准的spring .profiles.active属性,它定义了要启用的Spring配置文件的名称:

{
   
     "hints": [
    {
   
     
        "name": "spring.profiles.active",
        "providers": [
            {
   
     
                "name": "spring-profile-name"
            }
        ]
    }
]}

三、生成自己的元数据

通过使用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>

元数据自动生成

处理程序会选择带有@ConfigurationProperties注解的类和方法。
如果类有一个参数化构造函数,则每个构造函数参数创建一个"property",除非构造函数带有@Autowired注释。如果类有一个带有@ConstructorBinding显式注释的构造函数,则为该构造函数的每个构造函数参数创建一个"property"。否则,通过对集合和映射类型进行特殊处理的标准gettersetter来发现属性(即使只有getter也能检测到)。注解处理器还支持使用@Data@Value@Getter@Setter lombok注释。考虑以下例子:

@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 ...
}

这将公开三个属性,其中my.server.name没有默认值,my.server.ipmy.server.port分别默认为“127.0.0.1”和9797。字段上的Javadoc用于填充description属性。例如,my.server.ip的描述是“IP address to listen to”。

接下来编译项目,在target目录会生成META-INF/spring-configuration-metadata.json

 
元数据内容:
 
属性配置文件提示:
 

嵌套属性

注解处理器自动将内部类视为嵌套属性。如下例子:

@ConfigurationProperties(prefix = "my.server")
public class MyServerProperties {
   
     

    private String name;

    private Host host;

    // getters/setters ...

    public static class Host {
   
     

        private String ip;

        private int port;

        // 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完全相同。附加属性文件是可选的。如果没有任何其他属性,就不要添加该文件。

考虑以下例子:

@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 enum ContainerType {
   
     

        SIMPLE, DIRECT

    }

}

注解处理器无法自动检测EnumsCollections的默认值。
 
这种情况下可以使用手动添加元数据。

{
   
     "properties": [
    {
   
     
        "name": "my.messaging.addresses",
        "defaultValue": ["a", "b"]
    },
    {
   
     
        "name": "my.messaging.container-type",
        "defaultValue": "simple"
    }
]}

 

总结

本文主要介绍了Spring Boot元数据的概念以及作用,然后怎样创建自己的元数据,这为后面自定义Starter打下基础。
\