Spring註解@ConfigurationProperties

@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源碼:

參考資料:

發佈了34 篇原創文章 · 獲贊 31 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章