跳至主要內容

11. 特性-配置元数据

安图新大约 7 分钟

11. 特性-配置元数据

前言

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 会提示如下。
![ ][nbsp]
如果允许其它任意值,那么可以在添加额外元数据提供程序。

"hints": [
    {


      "name": "my.messaging.addresses",
      "values": [
        {


          "value": "a"
        },
        {


          "value": "b"
        }
      ],
      "providers": [
        {


          "name": "any"
        }
      ]
    }]

![ ][nbsp 1]

Class Reference

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

  "hints": [
    {


      "name": "server.servlet.jsp.class-name",
      "providers": [
        {


          "name": "class-reference",
          "parameters": {


            "target": "jakarta.servlet.http.HttpServlet"
          }
        }
      ]
    }

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

Handle As

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

 "hints": [
    {


      "name": "my.local",
      "providers": [
        {


          "name": "handle-as",
          "parameters": {


            "target": "org.springframework.core.io.Resource"
          }
        }
      ]
    }]

![ ][nbsp 3]
Handle As 支持的参数:

参数类型描述
targetString (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

![ ][nbsp 4]
元数据内容:
![ ][nbsp 5]
属性配置文件提示:
![ ][nbsp 6]

嵌套属性

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

@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的默认值。
![ ][nbsp 7]
这种情况下可以使用手动添加元数据。

{

     "properties": [
    {


        "name": "my.messaging.addresses",
        "defaultValue": ["a", "b"]
    },
    {


        "name": "my.messaging.container-type",
        "defaultValue": "simple"
    }
]}

![ ][nbsp 8]


总结

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

[Spring Boot 3.x]: https://blog.csdn.net/renpeng301/article/details/124325168 [nbsp]: https://cdn.hotmindshare.com/custom/images/2024/2/27/2044/1709037899238.png [nbsp 1]: https://cdn.hotmindshare.com/custom/images/2024/2/27/2044/1709037899725.png [nbsp 2]: https://cdn.hotmindshare.com/custom/images/2024/2/27/2045/1709037900132.png [nbsp 3]: https://cdn.hotmindshare.com/custom/images/2024/2/27/2045/1709037900275.png [nbsp 4]: https://cdn.hotmindshare.com/custom/images/2024/2/27/2045/1709037900706.png [nbsp 5]: https://cdn.hotmindshare.com/custom/images/2024/2/27/2045/1709037901171.png [nbsp 6]: https://cdn.hotmindshare.com/custom/images/2024/2/27/2045/1709037901839.png [nbsp 7]: https://cdn.hotmindshare.com/custom/images/2024/2/27/2045/1709037902365.png [nbsp 8]: https://cdn.hotmindshare.com/custom/images/2024/2/27/2045/1709037902800.png