成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

@ImportResource導(dǎo)入的xml配置里的Bean能夠使用@PropertySource導(dǎo)入

fancyLuo / 3075人閱讀

摘要:關(guān)于使用這種方式我還有必要再說明一點(diǎn)若自己設(shè)置了加載屬性文件,這句代碼對此種場景就沒有必要了,配置的占位符也是能夠讀取到的。

每篇一句
大師都是偏執(zhí)的,偏執(zhí)才能產(chǎn)生力量,妥協(xié)是沒有力量的。你對全世界妥協(xié)了你就是空氣。所以若沒有偏見,哪來的大師呢
相關(guān)閱讀

【小家Spring】詳解PropertyPlaceholderConfigurer、PropertyOverrideConfigurer等對屬性配置文件Properties的加載和使用
【小家Spring】Spring中@PropertySource和@ImportResource的區(qū)別,以及各自的實(shí)現(xiàn)原理解析

【小家Spring】Spring中@Value注解有多強(qiáng)大?從原理層面去剖析為何它有如此大的“能耐“

對Spring感興趣可掃碼加入wx群:Java高工、架構(gòu)師3群(文末有二維碼)

前言

寫這篇文章的原動(dòng)力是由于昨晚深夜一個(gè)小伙伴咨詢我的一個(gè)問題(這位小伙伴這么晚了還在折騰,也是給個(gè)大大的贊),涉及到了如題方面的知識。
當(dāng)然促使我書寫本文最重要原因的是:這種從傳統(tǒng)Spring項(xiàng)目向SpringBoot遷移進(jìn)階的case,我個(gè)人認(rèn)為在現(xiàn)階段的環(huán)境下還是有較大概率出現(xiàn)的,因此推薦收藏本文,對你后續(xù)或許有所幫助~

情景描述

為了更直觀的說明問題所在,截圖部分聊天記錄如下:

這位小伙伴描述的問題還是蠻清晰,所以我還是很愿意跟他一起探討的~

勾起興趣還有一個(gè)原因:Spring對占位符提供了非常強(qiáng)大的支持,但基本上新手都還不能好好利用它和利用好它,更區(qū)分不清使用的規(guī)范和區(qū)別,本文也希望做點(diǎn)努力,能夠起到稍微一點(diǎn)的作用~
對此部分內(nèi)容若需要熱場,推薦可以先瀏覽一下這篇文章:【小家Spring】Spring中@PropertySource和@ImportResource的區(qū)別,以及各自的實(shí)現(xiàn)原理解析 可以看到,早在我這篇文章里我就說了這么一句話:

而剛好這個(gè)小伙伴的場景(其實(shí)我自己還并沒有遇到過此場景),就類屬于老項(xiàng)目SpringBoot新項(xiàng)目的一個(gè)遷移case,這時(shí)不結(jié)合分析,更待何時(shí)呢。

看到聊天記錄,部分小伙伴可能會想:把Bean拿出來配置不就行了嗎?或者key就寫在原來的屬性文件里唄?
其實(shí)對于職場老兵都能對此種現(xiàn)象給與理解和接受,畢竟有種叫理想化,有種叫是叫實(shí)際化~

因?yàn)槲也豢赡苜N出該小伙伴的源碼(畢竟人家是生產(chǎn)環(huán)境的代碼,咋可能貼出給大伙看呢?)so,接下來旨在說明這個(gè)問題,我就只好采用我的模擬大法嘍:

傳統(tǒng)Spring工程下使用

本處以一個(gè)傳統(tǒng)的Spring工程為例,模擬這種使用case。classpath下有如下兩個(gè)文件:
spring-beans.xml:


    
    

可以看到此xml配置Bean中使用了占位符:${diy.name}來引用下面屬性文件的屬性值~

my.properties:

diy.name = fsx-fsx

使用@ImportResource@PropertySource分別把它哥倆導(dǎo)入:

@ImportResource(locations = "classpath:spring-beans.xml")
@PropertySource("classpath:my.properties")
@Configuration
public class RootConfig {
}

運(yùn)行如下測試用例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RootConfig.class})
public class TestSpringBean {

    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private Environment environment;

    @Test
    public void test1() {
        Person bean = (Person) applicationContext.getBean("myPerson");
        System.out.println(bean);

        System.out.println(environment.getProperty("diy.name"));
    }

}

打印結(jié)果為:

Person{name="${diy.name}", age=18}
fsx-fsx

從結(jié)果中可以至少知道如下兩點(diǎn):

環(huán)境變量里是存在diy.name這個(gè)屬性k-v的。并且此處我附上截圖如下:

xml中的占位符并沒有被解析

若你對技術(shù)有敏感性的話,你會疑問為何占位符沒被解析但并沒有報(bào)錯(cuò)呢?
這個(gè)問題我在這篇文章:【小家Spring】Spring中@Value注解有多強(qiáng)大?從原理層面去剖析為何它有如此大的“能耐“ 里有過解釋,有興趣的可以點(diǎn)開看看(沒興趣的可以略過)

存在但又沒被解析,看似有點(diǎn)矛盾,難道Spring工程不支持這么用,作為職場老兵的你,答案肯定是否定的,那如何破呢?
其實(shí)解決起來非常簡單,我們只需要配置上一個(gè)PropertyResourceConfigurer即可:

    @Bean
    public PropertyResourceConfigurer propertyResourceConfigurer() {
        PropertyResourceConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        // 使用的PropertySourcesPlaceholderConfigurer,不用自己再手動(dòng)指定亦可處理占位符~~~
        // configurer.setLocation(new ClassPathResource("my.properties")); // 加載指定的屬性文件
        return configurer;
    }

再次運(yùn)行,打印如下:

Person{name="fsx-fsx", age=18}
fsx-fsx

完美~

關(guān)于xml配置Bean處理占位符問題,為了加深理解,亦可參考:【小家Spring】Spring IoC是如何使用BeanWrapper和Java內(nèi)省結(jié)合起來給Bean屬性賦值的

我想說:此處介紹的是注解版怎么處理占位符問題,若你仍舊是傳統(tǒng)的xml配置項(xiàng)目,至于具體使用哪個(gè)標(biāo)簽,小伙伴自行尋找咯~

我們知道PropertyResourceConfigurer它是個(gè)抽象類,它的三大實(shí)現(xiàn)子類除了上例使用的,還有其余兩大實(shí)現(xiàn)類:PropertyOverrideConfigurerPropertyPlaceholderConfigurer若注冊它哥倆可行嗎??? 行不行試試唄

使用PropertyOverrideConfigurer

PropertyOverrideConfigurer 利用屬性文件的相關(guān)信息,覆蓋XML 配置文件中Bean定義。它要求配置的屬性文件第一個(gè).前面是beanName來匹配,所以這個(gè)子類我看都不用看,它肯定不行(因?yàn)樗淖兞薻-v的結(jié)構(gòu))。

**其實(shí)上面說配置PropertyResourceConfigurer的實(shí)現(xiàn)類來處理是不太準(zhǔn)確的。
準(zhǔn)確的說應(yīng)該是配置PlaceholderConfigurerSupport的實(shí)現(xiàn)子類來處理Placeholder占位符更精確,特此糾正哈~**
使用PropertyPlaceholderConfigurer

其實(shí)大多數(shù)小伙伴對PropertyPlaceholderConfigurer比對PropertySourcesPlaceholderConfigurer熟悉多了,畢竟前者的年紀(jì)可大多了~
它哥倆都是PlaceholderConfigurerSupport的實(shí)現(xiàn)子類有能力能夠處理占位符

PropertySourcesPlaceholderConfigurer是Spring 3.1后提供的,希望用來取代PropertyPlaceholderConfigurer
    @Bean
    public PropertyResourceConfigurer propertyResourceConfigurer() {
        PropertyResourceConfigurer configurer = new PropertyPlaceholderConfigurer();
        //configurer.setLocation(new ClassPathResource("my.properties")); // 加載指定的屬性文件
        return configurer;
    }

運(yùn)行上面用例就報(bào)錯(cuò)了:

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder "diy.name" in value "${diy.name}"
    at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:172)
    at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124)

what?看打印結(jié)果,明明environment.getProperty("diy.name")從環(huán)境里能拿到這個(gè)key呀,怎么會報(bào)錯(cuò)呢???
這就是為何Spring3.1要提供一個(gè)PropertySourcesPlaceholderConfigurer旨在想代替掉此類的原因了。

但是,但是,但是把上配置中注掉的那行代碼放開(也就是說自己設(shè)置location從而把屬性文件加載進(jìn)來),就能正常work了。
關(guān)于使用這種方式我還有必要再說明一點(diǎn):若自己設(shè)置了location加載屬性文件,@PropertySource("classpath:my.properties")這句代碼對此種場景就沒有必要了,xml配置的占位符也是能夠讀取到的。但是但是但是,若注掉這句@PropertySource...,此時(shí)運(yùn)行輸出如下:

Person{name="fsx-fsx", age=18}
null

會發(fā)現(xiàn)environment.getProperty("diy.name")為null,也就是說該屬性值并不會存在應(yīng)用的環(huán)境內(nèi)了(但是xml的占位符已被成功解析)。從我的這個(gè)截圖中也能看出來環(huán)境里已經(jīng)沒它了:

至于這深處到底是什么原因,有興趣的可以輕點(diǎn)這里:【小家Spring】詳解PropertyPlaceholderConfigurer、PropertyOverrideConfigurer等對屬性配置文件Properties的加載和使用

==只new一個(gè)PropertyPlaceholderConfigurer報(bào)錯(cuò)原因分析:==
其實(shí)從源代碼處一眼就能看出來原因:

public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport {
    ...
    // 是否能被解析到值,重點(diǎn)在于入?yún)⒌倪@個(gè)Properties props是否有這個(gè)key,而這個(gè)參數(shù)需要追溯它的父類~
    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
        StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
        doProcessProperties(beanFactoryToProcess, valueResolver);
    }
    ...
}

// 從父類中看看props的傳值是啥~~~
public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport implements BeanFactoryPostProcessor, PriorityOrdered {
    ...
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        try {
            Properties mergedProps = mergeProperties();
            // Convert the merged properties, if necessary.
            convertProperties(mergedProps);
            // Let the subclass process the properties.
            // 抽象方法,交給子類~~~這里傳入的mergedProps,全部來自location~~~
            processProperties(beanFactory, mergedProps);
        } catch (IOException ex) {
            throw new BeanInitializationException("Could not load properties", ex);
        }
    }

    protected Properties mergeProperties() throws IOException {
        ...
        loadProperties(result);
        ...
    }
    // 從配置里的location里把屬性值都讀出來~~~~~
    protected void loadProperties(Properties props) throws IOException {
        if (this.locations != null) {
            for (Resource location : this.locations) {
                ...
                PropertiesLoaderUtils.fillProperties(props, new EncodedResource(location, this.fileEncoding), this.propertiesPersister);
                ...
            }
        }
    }
    ...
}

由此可見,若上述@Bean配置使用的是PropertyPlaceholderConfigurer,那必須手動(dòng)的把屬性文件設(shè)置location加載進(jìn)去才行,否則是讀取不到滴~

==那么問題來了,為何使用PropertySourcesPlaceholderConfigurer,只需要簡單的new一個(gè)就成了勒(并不需要手動(dòng)設(shè)置location)?==
一樣的,從源碼處一看便知,非常非常簡單:

// @since 3.1  直接實(shí)現(xiàn)了EnvironmentAware,說明此Bean可以拿到當(dāng)前環(huán)境Environment
public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware {
    ...
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        ...
        // 把環(huán)境屬性都放進(jìn)來~
        if (this.environment != null) {
            this.propertySources.addLast(
                new PropertySource(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
                    @Override
                    @Nullable
                    public String getProperty(String key) {
                        return this.source.getProperty(key);
                    }
                }
            );
        }
        // 把配置的屬性放進(jìn)來~~~
        PropertySource localPropertySource = new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());
        this.propertySources.addFirst(localPropertySource);
        ...
    }    
}

相信不用我做過多的解釋,就知道為何不用自己設(shè)置location,直接使用注解@PropertySource("classpath:my.properties")就好使了吧。這個(gè)時(shí)候環(huán)境截圖如下(注意:此處我截圖是基于已經(jīng)set了location的截圖哦):

what?雖然配置時(shí)候set了location去加載屬性文件,但是上面代碼中add進(jìn)去的屬性源environmentPropertieslocalProperties

public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties";
public static final String ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME = "environmentProperties";

兩個(gè)PropertySource都并沒有出現(xiàn)?
關(guān)于此,我這里就不再解釋了,哈哈。還是那句話,留給小伙伴們自己思考,若思考不明白的亦可掃碼入群探討哦~(當(dāng)然參照上面文章也是可行的)

SpringBoot工程下使用

關(guān)于在SpringBoot中使用,簡單到令人發(fā)指,畢竟SpringBoot的使命也是讓你使用它能夠簡單到木有朋友。
so,在SpringBoot工程下使用@ImportResource@PropertySource啥都不用配,它是能夠天然的直接work的~

==原因分析如下:==
一切得益于SpringBoot強(qiáng)悍的自動(dòng)化配置能力,它提供了這樣一個(gè)配置類:

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) // 最高優(yōu)先級
public class PropertyPlaceholderAutoConfiguration {

    // 注意此處使用的是PropertySourcesPlaceholderConfigurer
    // 并且你可以在本容器內(nèi)覆蓋它的默認(rèn)行為喲~~~~
    @Bean
    @ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

}

PropertyPlaceholderAutoConfiguration它被配置在了自動(dòng)配置包下的spring.factories文件里:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
...
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,
...

因此它會隨著工程啟動(dòng)而自動(dòng)生效。有了上面對Spring工程下的使用分析,此處就不用再花筆墨解釋了~

另外附加說明一點(diǎn):哪怕你的屬性不使用@PropertySource導(dǎo)入,而是寫在SB自帶的application.properties文件里,依舊是沒有問題的。
==原因分析如下:==
其實(shí)這個(gè)涉及到的是SpringBootapplication.properties的加載時(shí)機(jī)問題,因?yàn)楸疚膶?b>SB的介紹并不是重點(diǎn),因此此處我直接簡單的說出結(jié)論即止:

SpringBoot通過事件監(jiān)聽機(jī)制加載很多東西,加載此屬性文件用的是ConfigFileApplicationListener這個(gè)監(jiān)聽器

它監(jiān)聽到ApplicationEnvironmentPreparedEvent(環(huán)境準(zhǔn)備好后)事件后開始加載application.properties等文件

ApplicationEnvironmentPreparedEvent的事件發(fā)出是發(fā)生在createApplicationContext()之前~~~ 部分代碼如下:

public class SpringApplication {
    ...
    public ConfigurableApplicationContext run(String... args) {
        ...
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 此步驟 會發(fā)出ApplicationEnvironmentPreparedEvent事件
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        Banner printedBanner = printBanner(environment);
            
        // 開始創(chuàng)建,初始化容器~
        context = createApplicationContext();
        ...
    }
    ...
}

so,在SB環(huán)境下已經(jīng)早早把屬性都放進(jìn)環(huán)境內(nèi)了,借助它默認(rèn)配置好的PropertySourcesPlaceholderConfigurer來處理的,那可不能正常work嗎。一切都是這么自然,這或許就是SB的魅力所在吧~

關(guān)于小伙伴問題的解決

開頭提出了問題,肯定得解決問題嘛~~~如下圖

哈哈,雖然最終我并沒有直接的幫助解決問題,但是此問題給了我寫本文的動(dòng)力,總體還是不錯(cuò)的~

總結(jié)

本文通過一個(gè)小伙伴咨詢的小問題(真是小問題嗎?)引申比較詳細(xì)的說了Spring在處理占位符這塊的內(nèi)容(其實(shí)本并沒打算寫這么多的,尷尬~)
寫本文的目的開頭也說了,我認(rèn)為在SpringBoot還并非100%滲透的當(dāng)下,肯定有人會遇到從傳統(tǒng)Spring項(xiàng)目向SpringBoot過度的一個(gè)階段,而本文的描述或許能給你的遷移提供一種新的思路(特別是時(shí)間緊、任務(wù)重的時(shí)候),希望小伙伴們能有所收獲,peace~

知識交流
若文章格式混亂,可點(diǎn)擊:原文鏈接-原文鏈接-原文鏈接-原文鏈接-原文鏈接

==The last:如果覺得本文對你有幫助,不妨點(diǎn)個(gè)贊唄。當(dāng)然分享到你的朋友圈讓更多小伙伴看到也是被作者本人許可的~==

**若對技術(shù)內(nèi)容感興趣可以加入wx群交流:Java高工、架構(gòu)師3群
若群二維碼失效,請加wx號:fsx641385712(或者掃描下方wx二維碼)。并且備注:"java入群" 字樣,會手動(dòng)邀請入群**

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/75481.html

相關(guān)文章

  • Spring Boot啟動(dòng)過程及回調(diào)接口匯總

    摘要:創(chuàng)建及準(zhǔn)備創(chuàng)建。目前已知關(guān)心這個(gè)事件的有要注意的是在這個(gè)階段,里只有,是的加載工作的起點(diǎn)。原因是注入這些回調(diào)接口本身沒有什么意義。在其構(gòu)造函數(shù)內(nèi)部間接的給注冊了幾個(gè)與相關(guān)注解的處理器。 相關(guān)代碼在: https://github.com/chanjarster/spring-boot-all-callbacks 注:本文基于spring-boot 1.4.1.RELEASE, spri...

    Taonce 評論0 收藏0
  • 最渣 Spring Boot 文章

    摘要:如刪除臨時(shí)文件,清除緩存信息,讀取配置文件信息,數(shù)據(jù)庫連接等。提供的接口也可以滿足該業(yè)務(wù)場景。不同點(diǎn)中方法的參數(shù)為,而接口中方法的參數(shù)為數(shù)組。 spring-boot-starter-parent Maven的用戶可以通過繼承spring-boot-starter-parent項(xiàng)目來獲得一些合理的默認(rèn)配置。這個(gè)parent提供了以下特性: 默認(rèn)使用Java 8 使用UTF-8編碼 一...

    yanest 評論0 收藏0
  • Spring注解專題系列

    摘要:用法先創(chuàng)建個(gè)組件,,,分別在類上加上注解。發(fā)現(xiàn)有一個(gè)屬性源碼注釋這樣說的自動(dòng)檢測使用組件。在的方法中,表示不匹配,代表匹配。這就說明使用注冊組件有種方式。 Spring注解應(yīng)用篇--IOC容器Bean組件注冊 這是Spring注解專題系類文章,本系類文章適合Spring入門者或者原理入門者,小編會在本系類文章下進(jìn)行企業(yè)級應(yīng)用實(shí)戰(zhàn)講解以及spring源碼跟進(jìn)。 環(huán)境準(zhǔn)備 編譯器IDEA...

    CocoaChina 評論0 收藏0
  • Springboot自動(dòng)配置簡單分析

    摘要:簡單的說,就通過具體就是類作為入口,配合注解實(shí)現(xiàn)了自動(dòng)配置。注解讓自動(dòng)配置生效。接下來,從開始分析。這個(gè)同名方法中,創(chuàng)建了一個(gè)對象并調(diào)用了對象的成員方法。是類的對象,的方法中有解析的主要邏輯。分別對注解注解注解注解注解注解進(jìn)行解析。 Springboot使用的版本是2.1.6.RELEASE。簡單的說,Springboot就通過BeanFactoryPostProcessor(具體就是...

    buildupchao 評論0 收藏0
  • Spring Boot 參考指南(自動(dòng)配置

    摘要:許多配置示例已經(jīng)在上發(fā)布,它們使用配置。逐漸取代自動(dòng)配置自動(dòng)配置非侵入性,在任何時(shí)候,你都可以開始定義自己的配置來替換自動(dòng)配置的特定部分。最后,你還可以通過使用屬性來控制要排除的自動(dòng)配置類的列表。 15. 配置類 Spring Boot支持基于java的配置,雖然可以使用XML源的SpringApplication,但是我們通常建議你的主源是一個(gè)@Configuration類。通常,定...

    dendoink 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<