一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - springboot @Value實現獲取計算機中絕對路徑文件的內容

springboot @Value實現獲取計算機中絕對路徑文件的內容

2021-12-24 13:05mysgk Java教程

這篇文章主要介紹了springboot @Value實現獲取計算機中絕對路徑文件的內容,具有很好的參考價值,希望對大家有所幫助。

springboot @Value獲取絕對路徑文件的內容

默認情況下使用

@Value("aaa.txt")
private Resource txtResource;

這樣獲取到的是項目classpath 下的 aaa.txt

如果想獲取非項目路徑下的文件內容怎么辦呢,看了下@Value的好像也沒有說,

其實

@Value("https://www.baidu.com")
private Resource urlResource;

這樣是可以獲取到 百度首頁的內容的.它這里使用的是https協議.

同樣的我們可以使用file協議獲取文本的內容

即:

@Value("file:///E://aaa.txt")
private Resource txtResource;

使用@Value 有一個好處就是,你不用關心文本內容的變化,你每次調用的時候,springboot 會自動幫你重新加載.

 

Spring注解@Value解讀

主要通過源碼解讀來分析@Value實現屬性注入Spring Bean的過程,并對static類型字段無法通過@Value注入為Spring Bean依賴的原因做一個探究。

依賴注入概述

基于Spring MVC或者Spring Boot開發后端項目的時候總是繞不開Spring IOC容器,Spring IOC容器管理Spring Bean,我們可以通過XML或者注解的方式來定義一個Bean,如通過注解@Service,@Controller,@Component,@Repository或者@Bean加Java配置方式。實際應用中我們定義的一個Bean很多時候存在互相之間的依賴,比如Service層通過@Service定義的Bean往往要依賴數據庫DAO層通過@Repository定義的Bean,這時候我們往往通過@Autowired或@Resource來自動裝配,另外還有一些Bean內部的屬性(Field)需要通過配置文件中定義的值來設置,而后創建的Bean才是符合我們預期的,我們一般通過@Value和@ConfigurationProperties來實現屬性的注入。

實際應用案例

以文檔管理服務為例,我們有個資源上傳的接口,其依賴一個FeignClient客戶端Bean,一個業務邏輯處理的Service Bean,還依賴一個資源上傳的OSS的桶bucket成員變量,bucket和OSS我們通常配置在配置文件中以區分不同環境。具體的依賴關系如下圖:

springboot @Value實現獲取計算機中絕對路徑文件的內容

源碼解讀分析

首先看一下Spring Bean的的整個生命周期:

springboot @Value實現獲取計算機中絕對路徑文件的內容

在實例化對象完成后,設置屬性值(polulateBean)之前,會搜集類上的注解元數據信息,然后在polulalteBean中攔截,執行BeanPostProcessor中的方法,反射注入依賴的值。@Resource是jdk提供的注解,其使用的后置處理器是CommonAnnotationBeanPostProcessor,而@Autowired和@Value注解使用的后置處理器是AutowiredAnnotationBeanPostProcessor,具體的我們下面會通過代碼來解讀。

先來看一下BeanFactory和ApplicationContext在裝載bean時候的區別:

  • BeanFactory在啟動時不會去實例化Bean,當從容器中拿Bean的時候才會去實例化;
  • ApplicationContext在啟動時就把所有的Bean全部實例化了。可以為Bean配置lazy-init=true來讓Bean延遲實例化。

我們下面以Spring Boot和ApplicationContext來走讀一下源碼:

1、首先進入SpringApplication.run(XXXApplication.class, args)

然后一直進入到SpringApplication的refreshContext()方法,refreshContext()是IOC容器初始化的核心方法,完成容器上下文的刷新,主要包括各種處理器、監聽器以及Bean的初始化等工作。

springboot @Value實現獲取計算機中絕對路徑文件的內容

2、然后進入到AbstractApplicationContext的refresh()方法

中的finishBeanFactoryInitialization(beanFactory)方法,這個方法就是ApplicationContext完成Spring Bean實例化和初始化的關鍵方法。

springboot @Value實現獲取計算機中絕對路徑文件的內容

3、而后進入到DefaultListableBeanFactory的preInstantiateSingletons()方法

此方法就是獲取到所有的beanName,然后循環的去實例化+初始化bean,而實例化+初始化的方式就是調用其getBean(String name)方法,因此我們直接調到getBean(name) ,此方法的最終實現是在AbstractBeanFactory中,我們進入AbstractBeanFactory的getBean(beanName)查看,然后根據調用棧直接進入到AbstractBeanFactory的doGetBean(final String name, @Nullable final Class requiredType, @Nullable final Object[] args, boolean typeCheckOnly)方法中。這個方法代碼較多,我們直接查看我們要關注的核心代碼段如下:

springboot @Value實現獲取計算機中絕對路徑文件的內容

4、然后我們進入到AbstractAutowireCapableBeanFactory

createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法中,其中AbstractAutowireCapableBeanFactory是AbstractBeanFactory的一個子類,AbstractBeanFactory的createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)由AbstractAutowireCapableBeanFactory實現。createBean方法的核心是調用了AbstractAutowireCapableBeanFactory的doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args),我們直接查看doCreateBean方法。

springboot @Value實現獲取計算機中絕對路徑文件的內容

5、我們略過創建實例的過程

直接進入applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)方法。

springboot @Value實現獲取計算機中絕對路徑文件的內容

5.1、applyMergedBeanDefinitionPostProcessors方法

主要是循環所有后置處理器對beanDefinition做處理,我們之前說過@Value注解是通過AutowiredAnnotationBeanPostProcessor來處理的,我們直接進入AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)方法如下:

springboot @Value實現獲取計算機中絕對路徑文件的內容

其中的InjectionMetadata如下,它主要封裝了bean的全限定類名和這個類中所有帶有注解的成員屬性(字段或者其他bean)描述(PropertyDescriptor,可以簡單理解為帶注解的成員屬性和注解本身兩者的組合),當然也就包括由@Value注解的字段。

springboot @Value實現獲取計算機中絕對路徑文件的內容

5.2、我們繼續進入到

findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs)方法,通過buildAutowiringMetadata(final Class<?> clazz)首先獲取了當前bean所屬類的屬性注解元數據,然后存儲到了injectionMetadataCache緩存中,完成了applyMergedBeanDefinitionPostProcessors方法。

springboot @Value實現獲取計算機中絕對路徑文件的內容

5.3、我們進入到

buildAutowiringMetadata(final Class<?> clazz)查看構建bean注入注解元數據的過程

springboot @Value實現獲取計算機中絕對路徑文件的內容

其中用到了獲取當前成員屬性AnnotationAttributes的方法findAutowiredAnnotation(AccessibleObject ao)如下:

springboot @Value實現獲取計算機中絕對路徑文件的內容

其中autowiredAnnotationTypes表示后置處理器AutowiredAnnotationBeanPostProcessor處理的注解列表,初始化如下:

springboot @Value實現獲取計算機中絕對路徑文件的內容

6、第5步完成了AbstractAutowireCapableBeanFactory

doCreateBean方法中的applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName),即完成了bean的成員屬性注解元數據的本地緩存。可以理解applyMergedBeanDefinitionPostProcessors為一個攔截器,即在對bean進行成員屬性和依賴注入前先預處理bean的依賴和成員屬性數據的解析和緩存,而后再進行populateBean。

6.1、進入到AbstractAutowireCapableBeanFactory

populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)方法,我們直接看核心代碼如下,其中postProcessProperties方法就是完成了bean的成員屬性的初始化和依賴的注入過程。

springboot @Value實現獲取計算機中絕對路徑文件的內容

6.2、因為我們要處理的是@Value和@Autowired注解的bean依賴

AutowiredAnnotationBeanPostProcessor是InstantiationAwareBeanPostProcessor接口的實現類,所以上面代碼端循環過程中會進入到之前的AutowiredAnnotationBeanPostProcessor的postProcessProperties(PropertyValues pvs, Object bean, String beanName)。

springboot @Value實現獲取計算機中絕對路徑文件的內容

6.3、上面findAutowiringMetadata方法就是第5.2步的方法

也就是從緩存Map中取出bean對應的注解元數據,而后調用InjectionMetadata的inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs)方法執行依賴注入過程。

springboot @Value實現獲取計算機中絕對路徑文件的內容

6.4、在上面對注解元數據列表循環處理(bean依賴了多個其他的bean或者多個成員屬性通過配置注入)進行依賴注入

調用element.inject(target, beanName, pvs)方法。而AutowiredAnnotationBeanPostProcessor類的內部類AutowiredFieldElement繼承了InjectionMetadata.InjectedElement類,并重寫了其inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)方法,AutowiredAnnotationBeanPostProcessor類的內部類AutowiredMethodElement也繼承了InjectionMetadata.InjectedElement類,并重寫了其inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)方法,因此6.3中的inject調用將會在此子類中執行,AutowiredFieldElement處理成員屬性上注解,AutowiredMethodElement處理方法上注解。因此@Value注解的處理將會進入到AutowiredFieldElement的inject方法。

springboot @Value實現獲取計算機中絕對路徑文件的內容

6.5、首先通過beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter)方法解析依賴

然后注冊當前bean依賴的其他bean,最后通過反射將依賴注入到當前bean中完成bean的依賴注入過程。DefaultListableBeanFactory繼承了AbstractAutowireCapableBeanFactory類,我們先查看DefaultListableBeanFactory的resolveDependency方法,其中主要是調用了DefaultListableBeanFactory的doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter)方法,我們直接看doResolveDependency方法。

springboot @Value實現獲取計算機中絕對路徑文件的內容

6.6、以上解析@Value注解

getSuggestedValue返回的值就是${xxx.documentcenter.bucketName:ssdocumentcenterstatic},因為是字符串,所以進入到下面的邏輯AbstractBeanFactory的resolveEmbeddedValue(@Nullable String value)方法中。resolveEmbeddedValue將完成@Value注解值的解析過程,最終得到配置文件中配置的值ssdocumentcenterstatic。下面的TypeConverter的convertIfNecessary主要完成數據類型的轉換,比如配置文件中配置的Boolean類型,將String轉為Boolean等。最后返回value值并注入到bean中,此成員屬性注入到bean的過程就完成了。我們簡單看一下resolveEmbeddedValue解析過程,主要通過AbstractPropertyResolver解析器完成,其內部使用了默認的占位符如下:

springboot @Value實現獲取計算機中絕對路徑文件的內容

通過其doResolvePlaceholders(String text, PropertyPlaceholderHelper helper)方法完成解析,內部調用了PropertyPlaceholderHelper的parseStringValue(String value, PlaceholderResolver placeholderResolver, Set visitedPlaceholders)方法來具體實現注解的值的解析和占位替換。解析首先是從配置文件對應的PropertySource中完成配置和值讀取,最終通過MapPropertySource實現。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://www.cnblogs.com/mysgk/p/9427282.html

延伸 · 閱讀

精彩推薦
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
主站蜘蛛池模板: 欧美一区二区三区综合色视频 | 亚洲高清视频免费 | 青草娱乐极品免费视频 | 和老外3p爽粗大免费视频 | 国产播放啪视频免费视频 | 深夜在线观看网站 | 美女脱得一二净无内裤全身的照片 | 亚洲sss综合天堂久久久 | 国产偷窥女洗浴在线观看亚洲 | 国产精品永久免费视频 | 秋霞理论在一l级毛片 | 男人v天堂 | 西野翔全部作品在线观看 | 喜欢老头吃我奶躁我的动图 | 久久综合色超碰人人 | 精品国产91久久久久 | ova巨公主催眠1在线观看 | 欧美美女被艹 | 男人j放进女人的p免费看视频 | 亚洲六月丁香六月婷婷蜜芽 | 亚洲AV无码A片在线观看蜜桃 | 波多野结衣黑人系列在线观看 | 亚洲精品国产一区二区三区在 | 久久这里只有精品视频e | 亚洲精品tv久久久久久久久久 | 67194最新网址 | 激情六月丁香婷婷四房播 | 蜜桃88av | 五月天精品视频播放在线观看 | 亚洲精品91在线 | 国产精品拍拍拍福利在线观看 | 免费视频专区一国产盗摄 | 亚洲精品久久麻豆蜜桃 | 国产一级特黄aa大片在线 | 网站视频免费 | 国产成人在线播放视频 | 免费看黄色片网站 | 欧美yw193.c㎝在线观看 | 幸福草电视剧演员表介绍 | 四虎精品成人a在线观看 | 性夜夜春夜夜爽AA片A |