1 簡介
前面我們用一篇文章《【Spring】只想用一篇文章記錄@Value的使用,不想再找其它了(附思維導圖)》
詳細講解了在Spring中如何使用@Value
來實現我們對配置的需求,它功能強大、使用方便。但它也是有它的局限性的,比如對於郵件服務,我們配置有:
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個獨立的變量:
@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
完美解決了這個問題。現在我們來深入了解一下這個注解的強大之處。
2 啟動注解的三種方式
啟動@ConfigurationProperties
有三種方式,分別是:
(1)屬性類@ConfigurationProperties
+屬性類@Component
@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
等也是可以的。
(2)屬性類@ConfigurationProperties
+配置類@Bean
在配置類中通過@Bean
聲明:
@Configuration
public class Config {
@Bean
public PkslowProperties pkslowProperties(){
return new PkslowProperties();
}
}
(3)屬性類@ConfigurationProperties
+配置類@EnableConfigurationProperties
我們可以在Springboot啟動類中加上注解@EnableConfigurationProperties
來聲明:
@SpringBootApplication
@EnableConfigurationProperties(PkslowProperties.class)
public class ConfigurationPropertiesDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigurationPropertiesDemoApplication.class, args);
}
}
3 兩大優點
3.1 寬松的綁定規則
支持寬松的綁定規則,以下格式都可以識別為accountType
屬性:
pkslow.accountType=QQ
pkslow.accounttype=QQ
pkslow.account_type=QQ
pkslow.account-type=QQ
pkslow.ACCOUNT_TYPE=QQ
3.2 支持多種屬性類型
支持多種屬性類型,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
為持續時間屬性,可支持的單位有:
-
ns:nanosecond,納秒
-
us:microsecond,微秒
-
ms:millisecond,毫秒
-
s:second,秒
-
m :minute,分
-
h:hour,小時
-
d :day,天
不寫默認為毫秒,也可以通過注解@DurationUnit
來指定單位。
@DurationUnit(ChronoUnit.DAYS)
private Duration timeInDays;
DataSize
類似,用來表示文件大小,支持的單位有:B/KB/MB/GB/TB。默認單位為B
,可以用@DataSizeUnit
指定單位。
4 屬性轉換失敗處理
4.1 無法轉換的類型
有時配置錯誤,就會無法轉換成正常的類型,例如屬性為布爾類型,卻定義為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
。
4.2 未知的屬性
如果寫錯的不是配置的值,而是配置的項,會發生什么呢?
#Java類沒有該屬性myAppName
pkslow.myAppName=pkslow
結果是什么也不會發生。
因為在默認情況下,Springboot 會忽略那些不能識別的字段。如果你希望它在這種情況下啟動失敗,可以配置ignoreUnknownFields
為false
,默認是為true
的。這樣你就必須要刪除這個配置錯誤的屬性了。
@Component
@ConfigurationProperties(prefix = "pkslow", ignoreUnknownFields = false)
public class PkslowProperties {
}
有兩點需要注意:
(1)如果設置ignoreInvalidFields
為true
,則ignoreUnknownFields
不起作用;
(2)帶有 @ConfigurationProperties
的不同的類不要使用相同的前綴(命名空間),容易造成沖突,如某個屬性一個可用,一個不可用。
5 自定義轉換器
如前面講解的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();
}
}
完成以上,就可以使用自定義的屬性和配置了。
6 使用Spring Boot Configuration Processor
自定義的屬性在IDE中是有告警的,無法被識別成合法的配置。通過引入Springboot Configuration Processor可以解決這個問題,並且IDE還能啟動自動補全功能。
引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
6.1 完成自動補全
引入依賴后,重新build一下project就可以了。它會為我們創建一個Json格式的文件:
6.2 標記配置屬性為 Deprecated
把注解@DeprecatedConfigurationProperty
放在getter方法,該屬性還會被顯示為Deprecated:
@Component
@ConfigurationProperties(prefix = "pkslow")
public class PkslowProperties {
private String name;
@DeprecatedConfigurationProperty
public String getName() {
return name;
}
}
自動補全和Deprecated的效果如下:
7 總結
本文通過代碼案例詳細講解了@ConfigurationProperties
的使用,demo的代碼可關注公眾號后台回復”ConfigurationProperties“獲取。
歡迎關注公眾號<南瓜慢說>,將持續為你更新...
多讀書,多分享;多寫作,多整理。