亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

解決Spring中@Value注解取值為null問題

 更新時間:2023年08月29日 09:21:45   作者:bboyzqh  
近期應(yīng)用中因業(yè)務(wù)迭代需要接入 user 客戶端,接入后總是啟動失敗,報注冊 user bean 依賴的配置屬性為 null,所以接下來小編就和大家一起排查分析這個問題,感興趣的小伙伴跟著小編一起來看看吧

一、背景

近期應(yīng)用中因業(yè)務(wù)迭代需要接入 user 客戶端,接入后總是啟動失敗,報注冊 user bean 依賴的配置屬性為 null(如 appName,group 等都為空),示例代碼如下:

@Configuration
public class ConsumerBeanConfig {
  @Value("${project.name}")
  private String appName;
  @Value("${spring.hsf.group}")
  private String group;
  @Value("${spring.hsf.version}")
  private String version;
  @Bean
  public UserCommonContext userCommonContext() {
    UserCommonContext commonContext = new UserCommonContext();
    commonContext.setAppName(appName);
    return commonContext;
  }
  @Bean
  public HSFSpringConsumerBean userReadService() {
    HSFSpringConsumerBean consumer = new HSFSpringConsumerBean();
    consumer.setInterfaceClass(UserReadService.class);
    consumer.setVersion(version);
    consumer.setGroup(group);
    return consumer;
  }
  //......
}

二、@Value 取值為 null 原因分析

2.1. @Value 取值為 null 常見原因分析

常見現(xiàn)象一:類沒有交給 Spring 管理,比如類沒有加上 @Component 等注解

  • 錯誤案例
// 配置類
public class PeopleConfigValue {
    @Value("${people.name}")
    private String name;
    @Value("${people.age}")
    private String age;
    public PeopleConfigValue() {
    }
    // getter and setter...
}
// 測試類(以下取值為空)
PeopleConfigValue peopleConfigValue = new PeopleConfigValue();
System.out.println("get peopleConfigValue-name value " + peopleConfigValue.getName());
System.out.println("get peopleConfigValue-age value " + peopleConfigValue.getAge());
  • 正常案例
@Component
public class PeopleConfigValue {
    @Value("${people.name}")
    private String name;
    @Value("${people.age}")
    private String age;
    public PeopleConfigValue() {
    }
    // getter and setter...
}
// 測試類(以下取值正常)
PeopleConfigValue peopleConfigValue = SpringContextUtil.getBean(PeopleConfigValue.class);
System.out.println("get peopleConfigValue-name value " + peopleConfigValue.getName());
System.out.println("get peopleConfigValue-age value " + peopleConfigValue.getAge());

常見現(xiàn)象二:手動 new 對象實(shí)例,沒有從 Spring 容器中獲取

  • 錯誤案例
@Component
public class PeopleConfigValue {
    @Value("${people.name}")
    private String name;
    @Value("${people.age}")
    private String age;
    public PeopleConfigValue() {
    }
    // getter and setter...
}
// 測試類(以下取值為空)
PeopleConfigValue peopleConfigValue = new PeopleConfigValue();
System.out.println("get peopleConfigValue-name value " + peopleConfigValue.getName());
System.out.println("get peopleConfigValue-age value " + peopleConfigValue.getAge());
  • 正確案例,參考第一個現(xiàn)象。

常見現(xiàn)象三:使用 static 或 final 修飾成員變量

使用 static 或 final 修飾成員變量值不可改變,注解無法注入配置值。

  • 錯誤案例
@Component
public class PeopleConfigValue {
    @Value("${people.name}")
    private static String name;
    @Value("${people.age}")
    private static String age;
    public PeopleConfigValue() {
    }
    // getter
}
// 測試類(以下取值為空)
PeopleConfigValue peopleConfigValue = SpringContextUtil.getBean(PeopleConfigValue.class);
System.out.println("get peopleConfigValue-name value " + peopleConfigValue.getName());
System.out.println("get peopleConfigValue-age value " + peopleConfigValue.getAge());
  • 正確案例

    以下方式不推薦,作為 static 或 final 修飾成員變量值應(yīng)該是不可變的,以下可通過 setter 方式修改值:

@Component
public class PeopleConfigValue {
    private static String name;
    private static String age;
    public PeopleConfigValue() {
    }
    public static String getName() {
        return name;
    }
    @Value("${people.name}")
    public void setName(String nameValue) {
        name = nameValue;
    }
    public static String getAge() {
        return age;
    }
    @Value("${people.age}")
    public void setAge(String ageValue) {
        age = ageValue;
    }
}
// 測試類,取值正常
PeopleConfigValue peopleConfigValue = SpringContextUtil.getBean(PeopleConfigValue.class);
System.out.println("get peopleConfigValue-name value " + peopleConfigValue.getName());
System.out.println("get peopleConfigValue-age value " + peopleConfigValue.getAge());

2.2 案例原因分析

上述案例中 @Value 的使用方式是常規(guī)使用方式,不應(yīng)該出現(xiàn)問題,開始懷疑是與 Spring 應(yīng)用上下文 Bean 的初始化順序有關(guān),排查這個問題還是先摸清一下 Spring Boot 的啟動原理及 @Value 解析機(jī)制,直接上圖:

圖片箭頭指向即 SpringApplication 啟動階段,在這個過程中進(jìn)行 Bean 的實(shí)例化,進(jìn)一步細(xì)化 SpringApplication 啟動流程如下:

眾所周知,應(yīng)用中配置的 bean 在 Spring 啟動時會全部解析為 BeanDefinition(可視為 bean 的元信息,圖中第 2 步),同時 Spring 提供了 BeanFactoryPostProcessor 接口用于用戶擴(kuò)展(圖中第 5 步,比如在這里可以修改BeanDefinition 的元數(shù)據(jù)) ,最后在實(shí)例化 bean 過程時(SpringApplication 啟動流程圖中第 11.3 步)會讀取相應(yīng)的 BeanDefinition 進(jìn)行初始化。

回到 @Value 注解占位符的解析機(jī)制,@Value 注解占位符靠 PropertyResourceConfigurer 來解析(PropertySourcesPlaceholderConfigurer 會調(diào)用 PropertyResourceConfigurer 解析能力來解析占位符,并存儲到 propertySources 屬性集合中),而 PropertyResourceConfigurer 正是實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口,在 BeanFactory 后處理階段進(jìn)行了占位符替換,且 PropertyResourceConfigurer 的優(yōu)化級最低(這里有個風(fēng)險點(diǎn):任何應(yīng)用依賴的實(shí)現(xiàn) BeanFactoryPostProcessor 接口的 bean 都會比 PropertyResourceConfigurer 先執(zhí)行)。

理解了 Spring 的啟動機(jī)制和 @Value 注解占位符的解析機(jī)制,再排查應(yīng)用代碼發(fā)現(xiàn) UserCommonContext 也實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口,也就是說,出現(xiàn)了下述情況:

由于 UserCommonContext 依賴了 UserBeanConfig,導(dǎo)致 UserBeanConfig 提前初始化,但此時 @Value 中的占位符還未替換,那么 UserBeanConfig 中所有標(biāo)記 @Value 注解屬性都為 null,導(dǎo)致啟動失敗。

三、解決方案

上述情況雖然會導(dǎo)致 UserBeanConfig 中所有標(biāo)記 @Value 注解屬性都為 null,其他 bean 的配置就不要依賴 UserBeanConfig 中標(biāo)記 @Value 注解的屬性即可(不依賴干擾 bean 生命周期):

@Bean
public HSFSpringConsumerBean userReadService(@Value("${spring.hsf.version}") String version, @Value("${spring.hsf.group}") String group) {
    HSFSpringConsumerBean consumer = new HSFSpringConsumerBean();
    consumer.setInterfaceClass(UserReadService.class);
    consumer.setVersion(version);
    consumer.setGroup(group);
    return consumer;
}

以上就是解決Spring中@Value注解取值為null問題的詳細(xì)內(nèi)容,更多關(guān)于Spring @Value注解取值為null的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring boot Rabbitmq消息防丟失實(shí)踐

    Spring boot Rabbitmq消息防丟失實(shí)踐

    這篇文章主要介紹了Spring boot Rabbitmq消息防丟失實(shí)踐,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • 淺析Java中的 new 關(guān)鍵字

    淺析Java中的 new 關(guān)鍵字

    java中的new關(guān)鍵字是實(shí)例化對象,接下來本文通過一個案例給大家講解Java中的 new 關(guān)鍵字,感興趣的朋友可以參考下
    2016-08-08
  • java 反射getClass .class 的使用方法示例

    java 反射getClass .class 的使用方法示例

    這篇文章主要介紹了java 反射getClass .class 的使用方法,結(jié)合實(shí)例形式分析了java類反射機(jī)制的相關(guān)操作技巧,需要的朋友可以參考下
    2019-11-11
  • Java實(shí)現(xiàn)把文件壓縮成zip文件的示例代碼

    Java實(shí)現(xiàn)把文件壓縮成zip文件的示例代碼

    這篇文章主要為大家介紹了如何通過Java語言實(shí)現(xiàn)將文件壓縮成zip文件,本文中示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • 一篇文章帶你了解jdk1.8新特性--為什么使用lambda表達(dá)式

    一篇文章帶你了解jdk1.8新特性--為什么使用lambda表達(dá)式

    Lambda是一個匿名函數(shù),我們可以把Lambda表達(dá)式理解為是一段可以傳遞的代碼,本篇文章就帶你了解,希望能給你帶來幫助
    2021-08-08
  • 詳談Java幾種線程池類型介紹及使用方法

    詳談Java幾種線程池類型介紹及使用方法

    下面小編就為大家?guī)硪黄斦凧ava幾種線程池類型介紹及使用方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • seata springcloud整合教程與遇到的坑

    seata springcloud整合教程與遇到的坑

    seata 是alibaba 出的一款分布式事務(wù)管理器,他有侵入性小,實(shí)現(xiàn)簡單等特點(diǎn)。這篇文章主要介紹了seata springcloud整合教程與遇到的坑,需要的朋友可以參考下
    2021-07-07
  • 詳解java中spring里的三大攔截器

    詳解java中spring里的三大攔截器

    在本篇文章里我們給大家詳細(xì)講述了java中spring里的三大攔截器相關(guān)知識點(diǎn)以及用法代碼,需要的朋友們學(xué)習(xí)下。
    2018-10-10
  • Java數(shù)據(jù)脫敏的常用方式總結(jié)

    Java數(shù)據(jù)脫敏的常用方式總結(jié)

    大家好!今天我們要聊一聊數(shù)據(jù)脫敏,這個詞聽起來像特工電影里的高科技武器,其實(shí)它就是給敏感數(shù)據(jù)穿上“偽裝衣”,防止“壞人”偷 窺,Java 提供了多種數(shù)據(jù)脫敏方式,今天咱們來聊幾種經(jīng)典實(shí)用的“偽裝術(shù)”,感興趣的小伙伴跟著小編一起來看看吧
    2024-11-11
  • java 動態(tài)代理的方法總結(jié)

    java 動態(tài)代理的方法總結(jié)

    這篇文章主要介紹了java 動態(tài)代理的方法總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2017-04-04

最新評論