最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決Spring中@Value注解取值為null問(wèn)題

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

一、背景

近期應(yīng)用中因業(yè)務(wù)迭代需要接入 user 客戶(hù)端,接入后總是啟動(dòng)失敗,報(bào)注冊(cè) user bean 依賴(lài)的配置屬性為 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 常見(jiàn)原因分析

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

  • 錯(cuò)誤案例
// 配置類(lèi)
public class PeopleConfigValue {
    @Value("${people.name}")
    private String name;
    @Value("${people.age}")
    private String age;
    public PeopleConfigValue() {
    }
    // getter and setter...
}
// 測(cè)試類(lèi)(以下取值為空)
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...
}
// 測(cè)試類(lèi)(以下取值正常)
PeopleConfigValue peopleConfigValue = SpringContextUtil.getBean(PeopleConfigValue.class);
System.out.println("get peopleConfigValue-name value " + peopleConfigValue.getName());
System.out.println("get peopleConfigValue-age value " + peopleConfigValue.getAge());

常見(jiàn)現(xiàn)象二:手動(dòng) new 對(duì)象實(shí)例,沒(méi)有從 Spring 容器中獲取

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

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

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

  • 錯(cuò)誤案例
@Component
public class PeopleConfigValue {
    @Value("${people.name}")
    private static String name;
    @Value("${people.age}")
    private static String age;
    public PeopleConfigValue() {
    }
    // getter
}
// 測(cè)試類(lèi)(以下取值為空)
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)該是不可變的,以下可通過(guò) 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;
    }
}
// 測(cè)試類(lèi),取值正常
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)問(wèn)題,開(kāi)始懷疑是與 Spring 應(yīng)用上下文 Bean 的初始化順序有關(guān),排查這個(gè)問(wèn)題還是先摸清一下 Spring Boot 的啟動(dòng)原理及 @Value 解析機(jī)制,直接上圖:

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

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

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

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

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

三、解決方案

上述情況雖然會(huì)導(dǎo)致 UserBeanConfig 中所有標(biāo)記 @Value 注解屬性都為 null,其他 bean 的配置就不要依賴(lài) UserBeanConfig 中標(biāo)記 @Value 注解的屬性即可(不依賴(lài)干擾 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問(wèn)題的詳細(xì)內(nèi)容,更多關(guān)于Spring @Value注解取值為null的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java并發(fā)編程包JUC線程同步CyclicBarrier語(yǔ)法示例

    java并發(fā)編程包JUC線程同步CyclicBarrier語(yǔ)法示例

    這篇文章主要為大家介紹了java并發(fā)編程工具包JUC線程同步CyclicBarrier語(yǔ)法使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • Java中的Runnable,Callable,F(xiàn)uture,F(xiàn)utureTask的比較

    Java中的Runnable,Callable,F(xiàn)uture,F(xiàn)utureTask的比較

    這篇文章主要介紹了Java中的Runnable,Callable,F(xiàn)uture,F(xiàn)utureTask的比較的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • SpringMVC靜態(tài)資源配置過(guò)程詳解

    SpringMVC靜態(tài)資源配置過(guò)程詳解

    在javaweb項(xiàng)目中配置了DispatcherServlet的情況下,如果不進(jìn)行額外配置的話,幾乎所有的請(qǐng)求都會(huì)走這個(gè)servlet來(lái)處理,默認(rèn)靜態(tài)資源按路徑是訪問(wèn)不到的會(huì)報(bào)404錯(cuò)誤,下面就來(lái)講一講如何配置才能訪問(wèn)到靜態(tài)資源吧
    2022-08-08
  • 詳解Java實(shí)踐之適配器模式

    詳解Java實(shí)踐之適配器模式

    在計(jì)算機(jī)編程中,適配器模式(有時(shí)候也稱(chēng)包裝樣式或者包裝)將一個(gè)類(lèi)的接口適配成用戶(hù)所期待的。一個(gè)適配允許通常因?yàn)榻涌诓患嫒荻荒茉谝黄鸸ぷ鞯念?lèi)工作在一起,做法是將類(lèi)自己的接口包裹在一個(gè)已存在的類(lèi)中
    2021-06-06
  • Spring @Cacheable 的使用小結(jié)

    Spring @Cacheable 的使用小結(jié)

    @Cacheable是Spring框架中用于方法級(jí)緩存的注解,它主要用于減少方法調(diào)用的次數(shù),通過(guò)緩存方法的返回結(jié)果來(lái)提高應(yīng)用程序的性能,下面就來(lái)詳細(xì)的了解一下
    2026-02-02
  • SpringSecurity導(dǎo)致SpringBoot跨域失效的問(wèn)題解決

    SpringSecurity導(dǎo)致SpringBoot跨域失效的問(wèn)題解決

    本文主要介紹了SpringSecurity導(dǎo)致SpringBoot跨域失效的問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • 解決MybatisPlus批量插入數(shù)據(jù)報(bào)錯(cuò):Error getting generated key or setting result to parameter object問(wèn)題

    解決MybatisPlus批量插入數(shù)據(jù)報(bào)錯(cuò):Error getting generated 

    在使用MybatisPlus進(jìn)行批量插入數(shù)據(jù)時(shí)遇到空指針異常錯(cuò)誤,分析原因是由于主鍵生成策略導(dǎo)致的,嘗試通過(guò)設(shè)置useGeneratedKeys屬性解決問(wèn)題,但因批量插入方法限制,該方法未能成功,最終通過(guò)自定義mapper方法實(shí)現(xiàn)批量插入,解決了問(wèn)題
    2024-09-09
  • WebService教程詳解(一)

    WebService教程詳解(一)

    WebService,顧名思義就是基于Web的服務(wù)。它使用Web(HTTP)方式,接收和響應(yīng)外部系統(tǒng)的某種請(qǐng)求,接下來(lái)通過(guò)本文給大家介紹WebService教程詳解(一),對(duì)webservice教程感興趣的朋友一起學(xué)習(xí)吧
    2016-03-03
  • Java使用modbus4j實(shí)現(xiàn)modbus?tcp通訊

    Java使用modbus4j實(shí)現(xiàn)modbus?tcp通訊

    Modbus是由Modicon(現(xiàn)為施耐德電氣公司的一個(gè)品牌)在1979年發(fā)明的,是全球第一個(gè)真正用于工業(yè)現(xiàn)場(chǎng)的總線協(xié)議,本文主要介紹了java如何使用modbus4j實(shí)現(xiàn)modbus?tcp通訊,感興趣的可以了解下
    2023-12-12
  • springboot yml配置文件使用@project.xxxx@啟動(dòng)報(bào)錯(cuò)Do not use @ for indentation問(wèn)題

    springboot yml配置文件使用@project.xxxx@啟動(dòng)報(bào)錯(cuò)Do not 

    這篇文章主要介紹了springboot yml配置文件使用@project.xxxx@啟動(dòng)報(bào)錯(cuò)Do not use @ for indentation問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07

最新評(píng)論

西青区| 嘉祥县| 南皮县| 寿光市| 禹城市| 思南县| 巴彦淖尔市| 岳西县| 河池市| 芜湖市| 镇康县| 施甸县| 泾源县| 永靖县| 信阳市| 鄂尔多斯市| 东阳市| 禹州市| 新晃| 杂多县| 临沂市| 吉木乃县| 海门市| 桐城市| 南康市| 中牟县| 沾益县| 乌拉特前旗| 扶余县| 逊克县| 萝北县| 松江区| 石河子市| 修水县| 双牌县| 唐山市| 皋兰县| 枣强县| 布尔津县| 冀州市| 靖西县|