在使用springboot框架时,我们常会在application.properties等配置文件上完成配置,而框架内的属性配置都是有配置属性提示的,那这是如何做到的呢,这篇文章就来自定义配置属性
我们以springboot整合redis的配置文件例举,spring.data.redis.host 为配置redis服务端的 Ip-Host,那这个属性配置后是如何生效被使用的呢,我们可以查看 RedisProperties 类,注意到类上有 @ConfigurationProperties(prefix = "spring.data.redis") 注解信息,看到这里应该会明白,prefix就是配置属性的固定前缀,而host是对应了 RedisProperties 类中的host字段
但仅配置@ConfigurationProperties 到具体的配置类上,配置文件就可以自动提示对应的配置类属性了吗?答案是否定的
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
Spring Boot Configuration Annotation Processor
依赖为springboot的编译时注解处理器,可以在项目编译时在
target META-INF 目录下生成 spring-configuration-metadata.json 文件,该文件为自动提示依赖的文件
配置类
@ConfigurationProperties(prefix = "china.train")
@Component
public class CustomProperties {
/**
* 列车名字
*/
private String name;
/**
* 列车编号
*/
private String number;
/**
* 途径地区
*/
private List<String> routeAreas;
@NestedConfigurationProperty
private CaseEntity caseEntity;
/**
* 列车类型
*/
private TrainType trainType;
/**
* 售票方式
*/
private TicketWay ticketWay;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public List<String> getRouteAreas() {
return routeAreas;
}
public void setRouteAreas(List<String> routeAreas) {
this.routeAreas = routeAreas;
}
public TrainType getTrainType() {
return trainType;
}
public void setTrainType(TrainType trainType) {
this.trainType = trainType;
}
public CaseEntity getCaseEntity() {
return caseEntity;
}
public void setCaseEntity(CaseEntity caseEntity) {
this.caseEntity = caseEntity;
}
public TicketWay getTicketWay() {
return ticketWay;
}
public void setTicketWay(TicketWay ticketWay) {
this.ticketWay = ticketWay;
}
}
public enum TrainType {
D("动车"),
G("高铁"),
Z("直达"),
T("特快"),
;
private String type;
TrainType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
/**
* 售票方式
* @author yangqingwei
* @date 2023/5/6 13:24
*/
public enum TicketWay {
Online("线上"),
Offline("线下")
;
private String type;
TicketWay(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public class CaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 2592610237232397458L;
private String fieldOne;
private TestEnum enumField;
public String getFieldOne() {
return fieldOne;
}
public void setFieldOne(String fieldOne) {
this.fieldOne = fieldOne;
}
public TestEnum getEnumField() {
return enumField;
}
public void setEnumField(TestEnum enumField) {
this.enumField = enumField;
}
}
配置类除需注解@ConfigurationProperties外,可以注解@Component由spring容器管理
注意到我们针对caseEntity字段标注了@NestedConfigurationProperty,这是因为caseEntity为对象类型,通过标注该注解可以解析对象字段内容,类如china.train.case-entity.enum-field,否则只到china.train.case-entity,除用注解标注该字段外,把该字段的对象类添加到CustomProperties 类中也可达到一致的效果
配置文件
china.train.name=hexiehao
china.train.route-areas=hangzhou,nanjing,hefei,wuhan
china.train.number=D2243
china.train.train-type=t
china.trian.additional=china
china.train.ticket-way=offline
china.train.case-entity.enum-field=one
china.train.case-entity.field-one=fieldOne
spring-configuration-metadata.json
{
"groups": [
{
"name": "china.train",
"type": "com.yangqingwei.client.config.CustomProperties",
"sourceType": "com.yangqingwei.client.config.CustomProperties"
},
{
"name": "china.train.case-entity",
"type": "com.yangqingwei.client.model.CaseEntity",
"sourceType": "com.yangqingwei.client.config.CustomProperties",
"sourceMethod": "getCaseEntity()"
}
],
"properties": [
{
"name": "china.train.case-entity.enum-field",
"type": "com.yangqingwei.client.model.enums.TestEnum",
"sourceType": "com.yangqingwei.client.model.CaseEntity"
},
{
"name": "china.train.case-entity.field-one",
"type": "java.lang.String",
"sourceType": "com.yangqingwei.client.model.CaseEntity"
},
{
"name": "china.train.name",
"type": "java.lang.String",
"description": "列车名字",
"sourceType": "com.yangqingwei.client.config.CustomProperties"
},
{
"name": "china.train.number",
"type": "java.lang.String",
"description": "列车编号",
"sourceType": "com.yangqingwei.client.config.CustomProperties"
},
{
"name": "china.train.route-areas",
"type": "java.util.List<java.lang.String>",
"description": "途径地区",
"sourceType": "com.yangqingwei.client.config.CustomProperties"
},
{
"name": "china.train.ticket-way",
"type": "com.yangqingwei.client.model.enums.TicketWay",
"description": "售票方式",
"sourceType": "com.yangqingwei.client.config.CustomProperties"
},
{
"name": "china.train.train-type",
"type": "com.yangqingwei.client.model.enums.TrainType",
"description": "列车类型",
"sourceType": "com.yangqingwei.client.config.CustomProperties"
},
{
"name": "china.trian.additional",
"type": "java.lang.String",
"description": "附加属性.",
"defaultValue": "china"
}
],
"hints": []
}
additional-spring-configuration-metadata.json
不知大家是否注意到 china.trian.additional=china 配置项,additional属性并未出现在配置类CustomProperties中,这是怎么做的呢?
我们将额外需要扩展的属性以 spring-configuration-metadata.json 相同的文件格式内容,命名为
additional-spring-configuration-metadata.json 添加到 resources 的 META-INF 目录下,在项目编译时,spring-boot-configuration-processor 会自动整合 additional-spring-configuration-metadata.json 中的内容到 target spring-configuration-metadata.json中,算是对配置类的功能扩展