@ConfigurationProperties是一個外部化配置註解,比如外部的.properties
屬性文件。使用該註解,可以實現把外部的屬性綁定到Bean實例,也可以實現在綁定的過程對外部屬性進行合法性驗證。
一、@ConfigurationProperties如何使用
@ConfigurationProperties註解通常放在類上使用,比如:
@ConfigurationProperties(prefix = "student",ignoreInvalidFields = false,ignoreUnknownFields = false)
public class StudentProperties {}
也可以在放在@Configuration註解的類裏面的@Bean註解的方法上,比如:
@Configuration
public class TeacherConfig {
@Bean
@ConfigurationProperties(prefix = "teacher")
public Teacher teacher(){//Spring會把@ConfigurationProperties註解的外部配置綁定到new Teacher()生成的實例對應屬性上
return new Teacher();
}
}
注意:@ConfigurationProperties註解並不會去實例化Bean,也不會把實例化的Bean加入IOC容器,只是對實例後的Bean進行屬性綁定以及驗證屬性值合法性。也
就是說@ConfigurationProperties註解不能單獨使用,通常要和其它能實例化Bean並把Bean加入IOC容器的註解配合才能生效,通常有以下三種方案:
(1). @ConfigurationProperties+@Configuration/@Component
@Configuration
@ConfigurationProperties(prefix = "")
public class StudentProperties {}
(2). @ConfigurationProperties+@EnableConfigurationProperties(Xxx.class)
@ConfigurationProperties(prefix = "")
public class StudentProperties {}
@EnableConfigurationProperties(StudentProperties.class)
@SpringBootApplication
public class ConfigurationPropertiesApplication implements ApplicationRunner {
@Autowired
private StudentProperties studentProperties;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(studentProperties.toString());
}
}
@EnableConfigurationProperties源碼解讀:
Enable support for {@link ConfigurationProperties @ConfigurationProperties} annotated beans. {@code @ConfigurationProperties} beans can be registered in the standard way (for example using {@link Bean @Bean} methods) or, for convenience, can be specified directly on this annotation.
開啓對@ConfigurationProperties註解Bean的支持,把@ConfigurationProperties註解的Bean註冊進IOC容器。換句話說,Spring會掃描開啓了@ConfigurationProperties註解的類進行實例化,並把@ConfigurationProperties指定前綴的屬性值綁定到類實例。
(3).@ConfigurationProperties+@ConfigurationPropertiesScan
@ConfigurationProperties(prefix = "student",ignoreInvalidFields = false,ignoreUnknownFields = false)
public class StudentProperties {}
@ConfigurationPropertiesScan
@SpringBootApplication
public class ConfigurationPropertiesApplication implements ApplicationRunner {
@Autowired
private StudentProperties studentProperties;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(studentProperties.toString());
}
}
@ConfigurationPropertiesScan
看源碼,Spring會掃描@ConfigurationPropertiesScan註解配置的包/類中@ConfigurationProperties註解的類進行實例化,然後把@ConfigurationProperties指定前綴的屬性值綁定到類實例,並加入IOC容器。
二、@ConfigurationProperties註解類屬性值綁定方式
(1)通過@ConfigurationProperties註解的類Setter方法
這種方式要求@ConfigurationProperties註解的類的屬性必須要有Setter方法
(2)通過@ConfigurationProperties註解的類構造方法
通過構造方法來進行屬性值綁定,必須使用@ConstructorBinding
註解到類上或者構造方法上指定屬性值綁定方式爲構造函數綁定。比如:
@ConfigurationProperties(prefix = "student",ignoreInvalidFields = false,ignoreUnknownFields = false)
public class StudentProperties {
@ConstructorBinding
public StudentProperties(String name, int age, Grade grade, School school, List<String> hobbyList, Duration allowLateTime) {
this.name = name;
this.age = age;
this.grade = grade;
this.school = school;
this.hobbyList = hobbyList;
this.allowLateTime = allowLateTime;
}
}
三、屬性值無法綁定時,重寫Converter 或 ConditionalConverter
接口來解決
如果.properties
文件的屬性值無法綁定到@ConfigurationProperties
註解的類屬性時,可以針對該屬性自定義轉換器來解決。自定義轉換器必須實現Converter 或ConditionalConverter
接口。
自定義轉換器還必須使用@ConfigurationPropertiesBinding
註解指名自己是一個配置屬性綁定器,並加入IOC容器。在進行屬性值綁定時,Spring會從IOC容器找特定綁定器進行轉換綁定。比如:
#properties配置文件
student:
grade: 三年級
@ConfigurationProperties(prefix = "student",ignoreInvalidFields = false,ignoreUnknownFields = false)
public class StudentProperties {
/**
* 年級
*/
private Grade grade;
}
/**
* @desc: Grade轉換器
*/
@Component
@ConfigurationPropertiesBinding
public class GradeConverter implements Converter<String,Grade> {
@Override
public Grade convert(String source) {
Grade grade = new Grade();
grade.setName(source);
return grade;
}
}
/**
* @desc: 年級
*/
@ToString
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Grade {
private String name;
private String school;
}
四、屬性值驗證
(1)@ConfigurationProperties註解本身帶有非法屬性和未知屬性驗證
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationProperties {
/**
* Flag to indicate that when binding to this object invalid fields should be ignored.
* Invalid means invalid according to the binder that is used, and usually this means
* fields of the wrong type (or that cannot be coerced into the correct type).
* @return the flag value (default false)
*/
boolean ignoreInvalidFields() default false;
/**
* Flag to indicate that when binding to this object unknown fields should be ignored.
* An unknown field could be a sign of a mistake in the Properties.
* @return the flag value (default true)
*/
boolean ignoreUnknownFields() default true;
}
(2)使用hibernate validator或 javax.validation驗證框架進行驗證
@Validated
@Configuration
@ConfigurationProperties(prefix = "student",ignoreInvalidFields = false,ignoreUnknownFields = false)
public class StudentProperties {
@NotEmpty(message = "學生姓名不能爲空")
private String name;
}
五、使用 Spring Boot Configuration Processor完成自動補全
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
重新 build 項目之後,configuration processor會創建target/classes/META-INF/spring-configuration-metadata.json文件。
{
"groups": [
{
"name": "student",
"type": "com.mapc.annotation.StudentProperties",
"sourceType": "com.mapc.annotation.StudentProperties"
}
],
"properties": [
{
"name": "student.age",
"type": "java.lang.Integer",
"description": "年齡",
"sourceType": "com.mapc.annotation.StudentProperties",
"defaultValue": 0
},
{
"name": "student.name",
"type": "java.lang.String",
"description": "姓名",
"sourceType": "com.mapc.annotation.StudentProperties"
}]
}
Demo源碼: