经常使用Spring boot项目的小伙伴们可能会发现,当我们使用spring boot标准组件的配置项的时候,IDE无论是IDEA还是Eclipse都能够给出提示。那么,IDE是怎么知道Spring boot标准组件的配置项的元信息的呢,大家可能会说,IDE自动下载了Spring boot标准组件配置项的元信息,所以能给出提示了。那么,Spring boot标准组件配置项的元信息是以什么样的格式存放的,它放在什么地方呢?今天,我们就一起了解一下。
根据Spring boot官方文档附件二配置元数据项的介绍,我们可以了解到配置元数据文件位于 META-INF/spring-configuration-metadata.json 下的 jars中,它们使用 JSON 格式,项目归类为“组”或“属性”,附加值提示归类为“提示”。
接下来,我们创建一个用于演示的项目,项目结构如下:
lwk@harbin:~/Public/project/default/simagou$ tree
.
├── mvnw
├── mvnw.cmd
├── pom.xml
├── README.md
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── qwfys
│ │ │ └── app
│ │ │ └── simagou
│ │ │ ├── config
│ │ │ │ ├── SimagouAppConfig.java
│ │ │ │ ├── SimagouAppProperties.java
│ │ │ ├── controller
│ │ │ ├── SimagouApplication.java
│ │ │ │ ├── HelloController.java
│ │ │ ├── SimagouApplication.java
│ │ └── resources
│ │ ├── application.yml
│ │ └── META-INF
│ │ ├── additional-spring-configuration-metadata.json
lwk@harbin:~/Public/project/default/simagou$
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.8</version>
<relativePath/>
</parent>
<groupId>com.qwfys.app</groupId>
<artifactId>simagou</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>simagou</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- SimagouAppProperties
package com.qwfys.app.simagou.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = SimagouAppProperties.FILE_SERVICE_PREFIX,
ignoreUnknownFields = true)
public class SimagouAppProperties {
public static final String FILE_SERVICE_PREFIX = "simagou.file.service";
/**
* 下载
*/
private Download download;
/**
* 上传
*/
private Upload upload;
@Data
public static class Download {
/**
* 数据抓取
*/
private Fetch fetch;
/**
* 可供文件下载的资源文件目录
*/
private String path;
}
@Data
public static class Fetch {
/**
* 每次迭代数
*/
private int recordsOnce = 500;
/**
* 最大记录数,取值为0代表不做限制
*/
private int maxRecords = 0;
/**
* 最大列数,取值为0代表不做限制
*/
private int maxColumns = 0;
/**
* 感应数大小
*/
private ContainerType containerType = ContainerType.TINY;
public enum ContainerType {
/**
* 极小
*/
TINY(200, "TINY"),
/**
* 小
*/
SMELL(500, "SMELL"),
/**
* 中
*/
MIDDLE(1000, "MIDDLE"),
/**
* 大
*/
BIG(5000, "BIG"),
/**
* 极大
*/
GREAT(10000, "GREAT"),
;
int code;
String label;
private ContainerType(int code, String label) {
this.code = code;
this.label = label;
}
public int getCode() {
return code;
}
public String getLabel() {
return label;
}
}
}
@Data
public static class Upload {
/**
* 标签系统可供文件上传的资源文件目录
*/
private String path;
}
}
- LabelAppConfig
package com.qwfys.app.simagou.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SimagouAppConfig {
@Bean
public SimagouAppProperties getLabelAppProperties() {
SimagouAppProperties properties = new SimagouAppProperties();
properties.setDownload(getDownload());
properties.setUpload(upload());
return properties;
}
@Bean
public SimagouAppProperties.Upload upload() {
SimagouAppProperties.Upload upload = new SimagouAppProperties.Upload();
return upload;
}
@Bean
public SimagouAppProperties.Fetch getFetch() {
SimagouAppProperties.Fetch fetch = new SimagouAppProperties.Fetch();
return fetch;
}
@Bean
public SimagouAppProperties.Download getDownload() {
SimagouAppProperties.Download download = new SimagouAppProperties.Download();
download.setFetch(getFetch());
return download;
}
}
这个时候,我们进入项目根目录,执行打包命令:
mvn clean package -Dmaven.test.skip=true
我们发现在目录target/classes/META-INF/中生成了配置元数据文件spring-configuration-metadata.json。观察后发现,生成的文件中,部分属性项没有默认值提示,属性可选项列表也没有。根据官网文档,缺失的这些内容需要我们手动添加到文件src/main/resources/META-INF/additional-spring-configuration-metadata.json中。接下来,我们就手动补充一些属性项的相关配置信息吧。
- additional-spring-configuration-metadata.json
src/main/resources/META-INF/additional-spring-configuration-metadata.json
{
"properties": [
{
"name": "simagou.file.service.download.fetch.records-once"
},
{
"name": "simagou.file.service.download.fetch.container-type",
"defaultValue": "TINY"
}
],
"hints": [
{
"name": "simagou.file.service.download.fetch.records-once",
"type": "java.lang.Integer",
"values": [
{
"value": 200
},
{
"value": 500
},
{
"value": 1000
}
]
},
{
"name": "simagou.file.service.download.fetch.container-type",
"values": [
{
"value": "TINY",
"description": "极小"
},
{
"value": "SMELL",
"description": "小"
},
{
"value": "MIDDLE",
"description": "中"
},
{
"value": "BIG",
"description": "大"
},
{
"value": "GREAT",
"description": "极大"
}
]
}
]
}
接下来,我们继续用maven命令打包,命令同上,即:
mvn clean package -Dmaven.test.skip=true
这个时候,我们接着进入目录target/classes/META-INF/打开文件spring-configuration-metadata.json就会看到上面我们手动添加的属性项已经补充到该文件中了,内容如下所示:
- spring-configuration-metadata.json
target/classes/META-INF/spring-configuration-metadata.json
{
"groups": [
{
"name": "simagou.file.service",
"type": "com.qwfys.app.simagou.config.SimagouAppProperties",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties"
},
{
"name": "simagou.file.service.download",
"type": "com.qwfys.app.simagou.config.SimagouAppProperties$Download",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties"
},
{
"name": "simagou.file.service.download.fetch",
"type": "com.qwfys.app.simagou.config.SimagouAppProperties$Fetch",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties$Download"
},
{
"name": "simagou.file.service.upload",
"type": "com.qwfys.app.simagou.config.SimagouAppProperties$Upload",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties"
}
],
"properties": [
{
"name": "simagou.file.service.download.fetch.container-type",
"type": "com.qwfys.app.simagou.config.SimagouAppProperties$Fetch$ContainerType",
"description": "感应数大小",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties$Fetch",
"defaultValue": "TINY"
},
{
"name": "simagou.file.service.download.fetch.max-columns",
"type": "java.lang.Integer",
"description": "最大列数,取值为0代表不做限制",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties$Fetch",
"defaultValue": 0
},
{
"name": "simagou.file.service.download.fetch.max-records",
"type": "java.lang.Integer",
"description": "最大记录数,取值为0代表不做限制",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties$Fetch",
"defaultValue": 0
},
{
"name": "simagou.file.service.download.fetch.records-once",
"type": "java.lang.Integer",
"description": "每次迭代数",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties$Fetch",
"defaultValue": 500
},
{
"name": "simagou.file.service.download.path",
"type": "java.lang.String",
"description": "可供文件下载的资源文件目录",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties$Download"
},
{
"name": "simagou.file.service.upload.path",
"type": "java.lang.String",
"description": "标签系统可供文件上传的资源文件目录",
"sourceType": "com.qwfys.app.simagou.config.SimagouAppProperties$Upload"
}
],
"hints": [
{
"name": "simagou.file.service.download.fetch.container-type",
"values": [
{
"value": "TINY",
"description": "极小"
},
{
"value": "SMELL",
"description": "小"
},
{
"value": "MIDDLE",
"description": "中"
},
{
"value": "BIG",
"description": "大"
},
{
"value": "GREAT",
"description": "极大"
}
]
},
{
"name": "simagou.file.service.download.fetch.records-once",
"values": [
{
"value": 200
},
{
"value": 500
},
{
"value": 1000
}
]
}
]
}
这个时候IDE根据项目类路径目录就会探测到刚刚生成的文件spring-configuration-metadata.json,进而就可以在我们编辑application.properties或者application.yml的时候给出提示。
- application.yml
simagou:
file:
service:
download:
fetch:
records-once: 200
max-records: 100000
max-columns: 200
path: ${user.home}/.app/label/download
upload:
path: ${user.home}/.app/label/upload
- HelloController
package com.qwfys.app.simagou.controller;
import com.qwfys.app.simagou.config.LabelAppProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.RestController;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/hello")
public class HelloController {
private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
@Autowired
private LabelAppProperties labelAppProperties;
@GetMapping("/index")
public String sayHello() {
final LabelAppProperties.Fetch fetch = labelAppProperties.getDownload().getFetch();
final int maxRecords = fetch.getMaxRecords();
logger.info("maxRecords:{}",maxRecords)
return "Hello,Welcome to Hangzhou!"
}
}
怎么样,是不是很简单呢?