Spring Boot 2.0 @ConfigurationProperties 使用

引言

Spring Boot的一個便捷功能是外部化配置,能夠輕鬆訪問屬性文件中定義的屬性。本文將詳細介紹@ConfigurationProperties的使用。java

配置項目POM

  • 在pom.xml中定義Spring-Boot 爲parent
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.4.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  • 添加依賴web

    1. 添加web,由於咱們須要使用到JSR-303規範的Validator,若是不想使用web依賴,也能夠直接依賴hibernate-validator
    2. 添加spring-boot-configuration-processor,能夠在編譯時生成屬性元數據(spring-configuration-metadata.json).
    3. 添加lombok,能夠方便使用註釋處理器的功能省去Pojo定義中get set這些麻煩工做.
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--<dependency>-->
      <!--<groupId>org.hibernate.validator</groupId>-->
      <!--<artifactId>hibernate-validator</artifactId>-->
      <!--<version>6.0.11.Final</version>-->
      <!--<scope>compile</scope>-->
    <!--</dependency>-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>

例子編寫

首先定義一個DocumentServerProperties對象,下面這個文檔服務器配置是我假設的,主要是爲了演示屬性配置的大部分狀況spring

@Getter
@Setter
public class DocumentServerProperties {

    private String remoteAddress;
    private boolean preferIpAddress;
    private int maxConnections=0;
    private int port;
    private AuthInfo authInfo;
    private List<String> whitelist;
    private Map<String,String> converter;
    private List<Person> defaultShareUsers;

    @Getter
    @Setter
    public static class AuthInfo {

        private String username;
        private String password;
    }
}

綁定屬性配置

注意@ConfigurationProperties並無把當前類註冊成爲一個Spring的Bean,下面介紹@ConfigurationProperties配置注入的三種方式.json

  • 配合@Component註解直接進行注入
@ConfigurationProperties(prefix = "doc")
@Component
public class DocumentServerProperties {
    //代碼...
}
  • 使用@EnableConfigurationProperties,一般配置在標有@Configuration的類上,固然其餘@Component註解的派生類也能夠,不過不推薦.
@ConfigurationProperties(prefix = "doc")
public class DocumentServerProperties {
    //代碼...
}
@EnableConfigurationProperties
@Configuration
public class SomeConfiguration {
    private DocumentServerProperties documentServerProperties
       
    public SomeConfiguration(DocumentServerProperties documentServerProperties) {
        this.documentServerProperties = documentServerProperties;
    }

}
  • 使用@Bean方式在標有@Configuration的類進行注入,這種方式一般能夠用在對第三方類進行配置屬性註冊
@Configuration
public class SomeConfiguration {
    
    @Bean
    public DocumentServerProperties documentServerProperties(){
        return new DocumentServerProperties();
    }
    
    @ConfigurationProperties("demo.third")
    @Bean
    public ThirdComponent thirdComponent(){
        return new ThirdComponent();
    }

}

編寫配置文件

Spring-Boot中配置文件的格式有properties和yaml兩種格式,針對上面的配置對象分別寫了兩種格式的配置文件例子.服務器

  • Properties
doc.remote-address=127.0.0.1
doc.port=8080
doc.max-connections=30
doc.prefer-ip-address=true
#doc.whitelist=192.168.0.1,192.168.0.2
# 這種等同於下面的doc.whitelist[0] doc.whitelist[1]
doc.whitelist[0]=192.168.0.1
doc.whitelist[1]=192.168.0.2
doc.default-share-users[0].name=jack
doc.default-share-users[0].age=18
doc.converter.a=xxConverter
doc.converter.b=xxConverter
doc.auth-info.username=user
doc.auth-info.password=password
  • Yaml
doc:
  remote-address: 127.0.0.1
  port: 8080
  max-connections: 30
  prefer-ip-address: true
  whitelist: 
    - 192.168.0.1
    - 192.168.0.2
  default-share-users: 
    - name: jack
      age: 18
  converter: 
    a: aConverter
    b: bConverter
  auth-info:
    username: user
    password: password

在上面的兩個配置文件中,其實已經把咱們日常大部分能使用到的屬性配置場景都覆蓋了,可能還有一些特殊的未介紹到,好比Duration、InetAddress等。ide

增長屬性驗證

下面咱們利用JSR303規範的實現對DocumentServerProperties屬性配置類,添加一些常規驗證,好比Null檢查、數字校驗等操做,spring-boot

須要注意在Spring-Boot 2.0版本之後,若是使用JSR303對屬性配置進行驗證必須添加@Validated註解,使用方式以下片斷:ui

@ConfigurationProperties(prefix = "doc")
@Validated
public class DocumentServerProperties {
    @NotNull // 判斷不爲空的狀況
    private String remoteAddress;
    
    //限制端口只能是80-65536之間
    @Min(80)
    @Max(65536)
    private int port;
    //其餘代碼
}

在有些數狀況下,咱們但願自定義驗證器,有兩種方式能夠進行實現this

  1. 實現org.springframework.validation.Validator接口,而且在配置一個Bean名稱必須叫configurationPropertiesValidator,代碼以下:
public class UserLoginValidator implements Validator {

    private static final int MINIMUM_PASSWORD_LENGTH = 6;

    public boolean supports(Class clazz) {
       return UserLogin.class.isAssignableFrom(clazz);
    }

    public void validate(Object target, Errors errors) {
       ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "field.required");
       ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "field.required");
       UserLogin login = (UserLogin) target;
       if (login.getPassword() != null
             && login.getPassword().trim().length() < MINIMUM_PASSWORD_LENGTH) {
          errors.rejectValue("password", "field.min.length",
                new Object[]{Integer.valueOf(MINIMUM_PASSWORD_LENGTH)},
                "The password must be at least [" + MINIMUM_PASSWORD_LENGTH + "] characters in );
       }
    }
}
  1. 和上面同樣也是實現org.springframework.validation.Validator接口,不過是須要驗證的屬性配置類自己去實現這個接口
@ConfigurationProperties(prefix = "doc")
public class DocumentServerProperties implements Validator{
    @NotNull
    private String remoteAddress;
    private boolean preferIpAddress;
       //其餘屬性 
   
    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

    @Override
    public void validate(Object target, Errors errors) {
        //判斷邏輯其實能夠參照上面的代碼片斷
    }
}

特別注意:spa

  • 只有在須要使用JSR303規範實現的驗證器時,才須要對對象配置@Validated,剛剛上面兩種方式並不須要。
  • 第一種實現和第二種實現都是實現org.springframework.validation.Validator接口,可是前者是針對全局的,後者只針對實現這個接口的配置對象

關於上述兩點,我爲啥肯定? 來自ConfigurationPropertiesBinder的源碼片斷

private List<Validator> getValidators(Bindable<?> target) {
    List<Validator> validators = new ArrayList<>(3);
    if (this.configurationPropertiesValidator != null) {
        validators.add(this.configurationPropertiesValidator);
    }
    if (this.jsr303Present && target.getAnnotation(Validated.class) != null) {
            validators.add(getJsr303Validator());
    }
    if (target.getValue() != null && target.getValue().get() instanceof Validator) {
        validators.add((Validator) target.getValue().get());
    }
    return validators;
}

總結

經過上面的例子,咱們瞭解了@ConfigurationProperties的使用以及如何進行驗證,包括屬性驗證器的幾種實現方式.下個章節我會從源碼的角度分析屬性的加載,以及如何解析到Bean裏面去的。

相關文章
相關標籤/搜索