Spring的@Value註解使用實踐及一個經典的易錯場景

程序員拾山 發佈 2022-12-04T09:03:43.909628+00:00

Spring提供了@Value註解幫助我們注入一個自定義屬性或者對象,大大簡化了我們的操作。本文主要介紹了@Value註解使用的常見場景及使用方法,以及分享一個比較經典的易錯場景。

前言

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註解的使用方法,及一個容易出錯的寫法。在實際業務場景中,一般用於讀取自定義配置,提升代碼的擴展性,方便後期的維護。

學習技術,分享技術,期待與大家共同進步,也感謝您的點讚與關注。

關鍵字: