前言
Spring提供了@Value註解幫助我們注入一個自定義屬性或者對象,大大簡化了我們的操作。但是如果對其原理不清楚,有時也會遇到一些不可預期的bug。
本文主要介紹了@Value註解使用的常見場景及使用方法,以及分享一個比較經典的易錯場景。
如何使用
常見的使用方式有以下四種,請注意使用方式的不同。
//直接注入一個字符串
@Value("我是字符串")
private String str;
//注入系統參數、環境變量或者配置文件中的值
//注意此處用的是 ${}
@Value("${application.name}")
private String applicationName;
//注入一個Bean的屬性,其中person為bean的ID,name為其屬性
//注意此處用的是 #{}
@Value("${person.name}")
private String name;
//注入一個bean,person是我們定義的一個bean
//注意注入bean時使用是 #{}
@Value("#{person}")
private Person person;
實踐
1,注入一個字符串
@SpringBootApplication(scanBasePackages = "com.shishan.demo2023.*")
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("我是常量字符串")
private String str;
@PostConstruct
public void init() {
//列印常量字符串
System.out.println("str====" + str);
}
}
啟動我們的項目,可以看到控制台列印出我們注入的str的值:
2,注入一個自定義屬性
在application.properties配置文件中配置以下屬性:
spring.application.name=demo2023
server.port=8080
username=shishan
userpassword=123456
@SpringBootApplication(scanBasePackages = "com.shishan.demo2023.*")
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("${username}")
private String username;
@PostConstruct
public void init() {
//列印自定義屬性
System.out.println("username====" + username);
}
}
啟動項目,控制台列印出來我們自定義的屬性值:
3,注入一個bean
先定義一個bean,並通過@Bean注入Spring容器
@Data
public class Person {
private String name;
private Integer age;
}
@Component
public class PersonConfig {
@Bean
public Person person(){
Person person = new Person();
person.setName("男人or女人");
person.setAge(18);
return person;
}
}
通過@Value注入person對象:
@SpringBootApplication(scanBasePackages = "com.shishan.demo2023.*")
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("#{person}")
private Person person;
@PostConstruct
public void init() {
//列印自定義屬性
System.out.println("person====" + person);
}
}
啟動項目,可以看到控制台列印出了person對象的屬性:
4,注入一個對象的屬性
還以上面的person對象為例,使用@Value注入person.name。
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("#{person.name}")
private String personName;
@PostConstruct
public void init() {
//列印personName
System.out.println("personName====" + personName);
}
}
啟動項目,可以看到控制列印出了personName:
總結:使用@Value可以直接注入一個常量字符串,如果要注入一個自定義屬性,請使用$符,如果要注入一個對象或者對象的屬性,要使用#號。
重點:注入自定義屬性用${},注入對象用#{}。
@Value容易出錯的一個經典場景
當我們使用@Value注入一個自定義的屬性值時,有一個容易出錯的經典場景就是:我們自定義的屬性與系統環境變量屬性衝突了,系統環境變量會覆蓋掉我們的自定義屬性值,並且不會報錯。
場景復現:
在application.properties配置文件中配置如下屬性:
spring.application.name=demo2023
server.port=8080
//定義user.name為shishan
user.name=shishan
嘗試注入user.name:
@SpringBootApplication(scanBasePackages = "com.shishan.demo2023.*")
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("${user.name}")
private String username;
@PostConstruct
public void init() {
//列印username
System.out.println("username====" + this.username);
}
}
按照我們的預期,控制台應該列印出username=shishan,但是結果卻不是這樣的。
我們可以看到控制列印出的結果是usename====cc,cc是博主的電腦用戶名。
之所以出現這樣的結果,是因為user.name正好與博主的系統變量衝突了,Spring優先讀取了系統變量,而忽略了我們的自定義變量。
Spring查找匹配變量時,採用的是策略是匹配即返回,並不會一直匹配到最後一個屬性,我們可以在PropertySourcesPropertyResolver#getProperty方法中找到Spring匹配屬性的邏輯,感興趣的朋友可以翻閱源碼看一看。
建議我們在自定義屬性值時,可以使用比較獨特的前綴,比如業務+屬性名,儘量和一些重合度比較高的屬性名避開,這樣可以最大程度的避免這些錯誤。
最後
本文主要介紹了@Value註解的使用方法,及一個容易出錯的寫法。在實際業務場景中,一般用於讀取自定義配置,提升代碼的擴展性,方便後期的維護。
學習技術,分享技術,期待與大家共同進步,也感謝您的點讚與關注。