前面咱們用一篇文章《【Spring】只想用一篇文章記錄@Value的使用,不想再找其它了(附思惟導圖)》java
詳細講解了在Spring中如何使用@Value
來實現咱們對配置的需求,它功能強大、使用方便。但它也是有它的侷限性的,好比對於郵件服務,咱們配置有:spring
mail.hostname=smtp.qq.com mail.username=larry@qq.com mail.password=123456 mail.to=to@163.com mail.cc=cc@gmail.com
使用@Value
,咱們須要5個註解及5個獨立的變量:segmentfault
@Value("${mail.hostname}") private String hostname; @Value("${mail.username}") private String username; @Value("${mail.password}") private String password; @Value("${mail.to}") private List<String> to; @Value("${mail.cc}") private List<String> cc;
這樣很是不方便,容易出錯,較難維護,很差傳遞。若是能把相同功能的配置組合起來,那配置就不會這麼亂了。而Springboot
爲咱們提供了註解@ConfigurationProperties
完美解決了這個問題。如今咱們來深刻了解一下這個註解的強大之處。app
啓動@ConfigurationProperties
有三種方式,分別是:ide
(1)屬性類@ConfigurationProperties
+屬性類@Component
spring-boot
@Component @ConfigurationProperties(prefix = "pkslow") public class PkslowProperties { private String name; private List<String> emails; private Map<String, Integer> price; //getter and setter }
在屬性配置類上加註解@ConfigurationProperties
是三種方式都須要的,第一種方式經過@Component
聲明爲一個可用的Bean。實際不必定是@Component
,@Service
等也是能夠的。ui
(2)屬性類@ConfigurationProperties
+配置類@Bean
spa
在配置類中經過@Bean
聲明:code
@Configuration public class Config { @Bean public PkslowProperties pkslowProperties(){ return new PkslowProperties(); } }
(3)屬性類@ConfigurationProperties
+配置類@EnableConfigurationProperties
xml
咱們能夠在Springboot啓動類中加上註解@EnableConfigurationProperties
來聲明:
@SpringBootApplication @EnableConfigurationProperties(PkslowProperties.class) public class ConfigurationPropertiesDemoApplication { public static void main(String[] args) { SpringApplication.run(ConfigurationPropertiesDemoApplication.class, args); } }
支持寬鬆的綁定規則,如下格式均可以識別爲accountType
屬性:
pkslow.accountType=QQ pkslow.accounttype=QQ pkslow.account_type=QQ pkslow.account-type=QQ pkslow.ACCOUNT_TYPE=QQ
支持多種屬性類型,Java類以下:
@Component @ConfigurationProperties(prefix = "pkslow") @Data public class PkslowProperties { private String name; private List<String> emails; private Map<String, Integer> price; private Account mainAccount; private List<Account> emailAccounts; private Map<String, Account> friendAccounts; private Duration activeTime; private DataSize appFileSize; }
配置以下:
#普通類型 pkslow.name=Larry #List pkslow.emails[0]=larry@qq.com pkslow.emails[1]=larry@gmail.com #Map pkslow.price.shoe=200 pkslow.price.pen=10 pkslow.price.book=43 #Object pkslow.mainAccount.username=larry pkslow.mainAccount.password=123456 pkslow.mainAccount.accountType=Main #List<Object> pkslow.emailAccounts[0].username=larry pkslow.emailAccounts[0].password=****** pkslow.emailAccounts[0].accounttype=QQ pkslow.emailAccounts[1].username=larry pkslow.emailAccounts[1].password=xxxxxx pkslow.emailAccounts[1].account_type=Gmail pkslow.emailAccounts[2].username=larry pkslow.emailAccounts[2].password=xxxxxx pkslow.emailAccounts[2].account-type=163 pkslow.emailAccounts[3].username=larry pkslow.emailAccounts[3].password=xxxxxx pkslow.emailAccounts[3].ACCOUNT_TYPE=Apple #Map<String, Object> pkslow.friendAccounts.JJ.username=JJ pkslow.friendAccounts.JJ.password=****** pkslow.friendAccounts.JJ.accountType=QQ pkslow.friendAccounts.Larry.username=Larry pkslow.friendAccounts.Larry.password=****** pkslow.friendAccounts.Larry.accountType=QQ #Duration pkslow.activeTime=30d #DataSize pkslow.appFileSize=10KB
Duration
爲持續時間屬性,可支持的單位有:
不寫默認爲毫秒,也能夠經過註解@DurationUnit
來指定單位。
@DurationUnit(ChronoUnit.DAYS) private Duration timeInDays;
DataSize
相似,用來表示文件大小,支持的單位有:B/KB/MB/GB/TB。默認單位爲B
,能夠用@DataSizeUnit
指定單位。
有時配置錯誤,就會沒法轉換成正常的類型,例如屬性爲布爾類型,卻定義爲pkslow.enabled=open
,那確定是沒法轉換的。默認會啓動失敗,並拋出異常。
Description: Failed to bind properties under 'pkslow.enabled' to boolean: Property: pkslow.enabled Value: open Origin: class path resource [application.properties]:46:16 Reason: failed to convert java.lang.String to boolean Action: Update your application's configuration
但若是咱們並不想影響Springboot的啓動,能夠經過設置 ignoreInvalidFields
屬性爲 true (默認爲 false),就會忽略錯誤的屬性。
@Component @ConfigurationProperties(prefix = "pkslow", ignoreInvalidFields = true) public class PkslowProperties { }
設置以後,錯誤的屬性就會取默認值,如null
或false
。
若是寫錯的不是配置的值,而是配置的項,會發生什麼呢?
#Java類沒有該屬性myAppName pkslow.myAppName=pkslow
結果是什麼也不會發生。
由於在默認狀況下,Springboot 會忽略那些不能識別的字段。若是你但願它在這種狀況下啓動失敗,能夠配置ignoreUnknownFields
爲false
,默認是爲true
的。這樣你就必需要刪除這個配置錯誤的屬性了。
@Component @ConfigurationProperties(prefix = "pkslow", ignoreUnknownFields = false) public class PkslowProperties { }
有兩點須要注意:
(1)若是設置ignoreInvalidFields
爲true
,則ignoreUnknownFields
不起做用;
(2)帶有 @ConfigurationProperties
的不一樣的類不要使用相同的前綴(命名空間),容易形成衝突,如某個屬性一個可用,一個不可用。
如前面講解的Duration
和DataSize
,都是比較特殊的屬性。實際上咱們還能夠自定義屬性,並自定義轉換器來實現屬性綁定。
配置以下:
pkslow.convertAccount=Larry:123456:QQ
對應的屬性爲:
private Account convertAccount;
其中Account
類以下:
@Data @NoArgsConstructor @AllArgsConstructor public class Account { private String username; private String password; private String accountType; }
經過實現Converter
接口自定義轉換器以下:
public class AccountConverter implements Converter<String, Account> { @Override public Account convert(String s) { String[] strings = s.split(":"); return new Account(strings[0], strings[1], strings[2]); } }
經過註解@ConfigurationPropertiesBinding
聲明啓用該轉換器:
@Configuration public class Config { @Bean @ConfigurationPropertiesBinding public AccountConverter accountConverter() { return new AccountConverter(); } }
完成以上,就可使用自定義的屬性和配置了。
自定義的屬性在IDE中是有告警的,沒法被識別成合法的配置。經過引入Springboot Configuration Processor能夠解決這個問題,而且IDE還能啓動自動補全功能。
引入:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
引入依賴後,從新build一下project就能夠了。它會爲咱們建立一個Json格式的文件:
把註解@DeprecatedConfigurationProperty
放在getter方法,該屬性還會被顯示爲Deprecated:
@Component @ConfigurationProperties(prefix = "pkslow") public class PkslowProperties { private String name; @DeprecatedConfigurationProperty public String getName() { return name; } }
自動補全和Deprecated的效果以下:
本文經過代碼案例詳細講解了@ConfigurationProperties
的使用,demo的代碼可關注公衆號後臺回覆」ConfigurationProperties「獲取。
歡迎關注公衆號<南瓜慢說>,將持續爲你更新...
多讀書,多分享;多寫做,多整理。