欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot @Value實(shí)現(xiàn)獲取計(jì)算機(jī)中絕對(duì)路徑文件的內(nèi)容

 更新時(shí)間:2021年09月09日 11:24:06   作者:mysgk  
這篇文章主要介紹了springboot @Value實(shí)現(xiàn)獲取計(jì)算機(jī)中絕對(duì)路徑文件的內(nèi)容,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。

springboot @Value獲取絕對(duì)路徑文件的內(nèi)容

默認(rèn)情況下使用

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

這樣獲取到的是項(xiàng)目classpath 下的 aaa.txt

如果想獲取非項(xiàng)目路徑下的文件內(nèi)容怎么辦呢,看了下@Value的好像也沒(méi)有說(shuō),

其實(shí)

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

這樣是可以獲取到 百度首頁(yè)的內(nèi)容的.它這里使用的是https協(xié)議.

同樣的我們可以使用file協(xié)議獲取文本的內(nèi)容

即:

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

使用@Value 有一個(gè)好處就是,你不用關(guān)心文本內(nèi)容的變化,你每次調(diào)用的時(shí)候,springboot 會(huì)自動(dòng)幫你重新加載.

Spring注解@Value解讀

主要通過(guò)源碼解讀來(lái)分析@Value實(shí)現(xiàn)屬性注入Spring Bean的過(guò)程,并對(duì)static類型字段無(wú)法通過(guò)@Value注入為Spring Bean依賴的原因做一個(gè)探究。

依賴注入概述

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

實(shí)際應(yīng)用案例

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

源碼解讀分析

首先看一下Spring Bean的的整個(gè)生命周期:

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

先來(lái)看一下BeanFactory和ApplicationContext在裝載bean時(shí)候的區(qū)別:

  • BeanFactory在啟動(dòng)時(shí)不會(huì)去實(shí)例化Bean,當(dāng)從容器中拿Bean的時(shí)候才會(huì)去實(shí)例化;
  • ApplicationContext在啟動(dòng)時(shí)就把所有的Bean全部實(shí)例化了??梢詾锽ean配置lazy-init=true來(lái)讓Bean延遲實(shí)例化。

我們下面以Spring Boot和ApplicationContext來(lái)走讀一下源碼:

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

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

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

中的finishBeanFactoryInitialization(beanFactory)方法,這個(gè)方法就是ApplicationContext完成Spring Bean實(shí)例化和初始化的關(guān)鍵方法。

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

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

4、然后我們進(jìn)入到AbstractAutowireCapableBeanFactory

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

5、我們略過(guò)創(chuàng)建實(shí)例的過(guò)程

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

5.1、applyMergedBeanDefinitionPostProcessors方法

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

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

5.2、我們繼續(xù)進(jìn)入到

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

5.3、我們進(jìn)入到

buildAutowiringMetadata(final Class<?> clazz)查看構(gòu)建bean注入注解元數(shù)據(jù)的過(guò)程

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

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

6、第5步完成了AbstractAutowireCapableBeanFactory

doCreateBean方法中的applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName),即完成了bean的成員屬性注解元數(shù)據(jù)的本地緩存??梢岳斫鈇pplyMergedBeanDefinitionPostProcessors為一個(gè)攔截器,即在對(duì)bean進(jìn)行成員屬性和依賴注入前先預(yù)處理bean的依賴和成員屬性數(shù)據(jù)的解析和緩存,而后再進(jìn)行populateBean。

6.1、進(jìn)入到AbstractAutowireCapableBeanFactory

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

6.2、因?yàn)槲覀円幚淼氖茾Value和@Autowired注解的bean依賴

AutowiredAnnotationBeanPostProcessor是InstantiationAwareBeanPostProcessor接口的實(shí)現(xiàn)類,所以上面代碼端循環(huán)過(guò)程中會(huì)進(jìn)入到之前的AutowiredAnnotationBeanPostProcessor的postProcessProperties(PropertyValues pvs, Object bean, String beanName)。

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

也就是從緩存Map中取出bean對(duì)應(yīng)的注解元數(shù)據(jù),而后調(diào)用InjectionMetadata的inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs)方法執(zhí)行依賴注入過(guò)程。

6.4、在上面對(duì)注解元數(shù)據(jù)列表循環(huán)處理(bean依賴了多個(gè)其他的bean或者多個(gè)成員屬性通過(guò)配置注入)進(jìn)行依賴注入

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

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

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

6.6、以上解析@Value注解

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

通過(guò)其doResolvePlaceholders(String text, PropertyPlaceholderHelper helper)方法完成解析,內(nèi)部調(diào)用了PropertyPlaceholderHelper的parseStringValue(String value, PlaceholderResolver placeholderResolver, Set visitedPlaceholders)方法來(lái)具體實(shí)現(xiàn)注解的值的解析和占位替換。解析首先是從配置文件對(duì)應(yīng)的PropertySource中完成配置和值讀取,最終通過(guò)MapPropertySource實(shí)現(xiàn)。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java讀取圖片EXIF信息的方法

    Java讀取圖片EXIF信息的方法

    這篇文章主要介紹了Java讀取圖片EXIF信息的方法,較為詳細(xì)的分析了圖片EXIF信息的概念、功能及java讀取EXIF信息的實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2015-07-07
  • 學(xué)習(xí)SpringBoot容器功能及注解原理

    學(xué)習(xí)SpringBoot容器功能及注解原理

    這篇文章主要介紹了學(xué)習(xí)SpringBoot容器功能及注解原理,文中通過(guò)詳細(xì)的代碼示例對(duì)SpringBoot容器功能及注解原理進(jìn)行了解析,有需要的朋友可以借鑒參考下
    2021-09-09
  • IDEA新建Springboot項(xiàng)目(圖文教程)

    IDEA新建Springboot項(xiàng)目(圖文教程)

    下面小編就為大家?guī)?lái)一篇IDEA新建Springboot項(xiàng)目(圖文教程)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • JavaCV?本地視頻推流實(shí)現(xiàn)依賴示例

    JavaCV?本地視頻推流實(shí)現(xiàn)依賴示例

    這篇文章主要為大家介紹了JavaCV?本地視頻推流實(shí)現(xiàn)的依賴示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Java 中String StringBuilder 與 StringBuffer詳解及用法實(shí)例

    Java 中String StringBuilder 與 StringBuffer詳解及用法實(shí)例

    這篇文章主要介紹了Java 中String StringBuilder 與 StringBuffer詳解及用法實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Spring?Boot中使用Spring?Retry重試框架的操作方法

    Spring?Boot中使用Spring?Retry重試框架的操作方法

    這篇文章主要介紹了Spring?Retry?在SpringBoot?中的應(yīng)用,介紹了RetryTemplate配置的時(shí)候,需要設(shè)置的重試策略和退避策略,需要的朋友可以參考下
    2022-04-04
  • java打印指定年月的日歷

    java打印指定年月的日歷

    這篇文章主要為大家詳細(xì)介紹了Java如何打印指定年月的日歷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • SpringBoot如何集成Netty

    SpringBoot如何集成Netty

    這篇文章主要介紹了SpringBoot如何集成Netty問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Java 如何讀取Excel格式xls、xlsx數(shù)據(jù)工具類

    Java 如何讀取Excel格式xls、xlsx數(shù)據(jù)工具類

    這篇文章主要介紹了Java 如何讀取Excel格式xls、xlsx數(shù)據(jù)工具類的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java中String字符串轉(zhuǎn)具體對(duì)象的幾種常用方式

    Java中String字符串轉(zhuǎn)具體對(duì)象的幾種常用方式

    String對(duì)象可以用來(lái)存儲(chǔ)任何字符串類型的數(shù)據(jù),包括HTML、XML等格式的字符串,下面這篇文章主要給大家介紹了關(guān)于JavaString字符串轉(zhuǎn)具體對(duì)象的幾種常用方式,需要的朋友可以參考下
    2024-03-03

最新評(píng)論