SpringBoot 自動(dòng)配置失效的解決方法_第1頁(yè)
SpringBoot 自動(dòng)配置失效的解決方法_第2頁(yè)
SpringBoot 自動(dòng)配置失效的解決方法_第3頁(yè)
SpringBoot 自動(dòng)配置失效的解決方法_第4頁(yè)
SpringBoot 自動(dòng)配置失效的解決方法_第5頁(yè)
已閱讀5頁(yè),還剩4頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第SpringBoot自動(dòng)配置失效的解決方法目錄問題描述@EnableConfigurationProperties注解行為配置有效,AutoTestConfiguration未刷新

prefix-type@ConditionalOnProperty@ConditionalOnPropertymatch邏輯@ConditionalOnPropertyskip邏輯

總結(jié)本文源自近期項(xiàng)目中遇到的問題,bug總是出現(xiàn)在你自以為是的地方...

問題描述

下面是一個(gè)簡(jiǎn)單復(fù)現(xiàn)的代碼片段,在你沒有閱讀完本文時(shí),如果能做出正確的判斷,那恭喜你可以節(jié)省閱讀本文的時(shí)間了。

1、自動(dòng)配置類:AutoTestConfiguration

@Configuration

@EnableConfigurationProperties(TestProperties.class)

@ConditionalOnProperty(prefix="test",name="enable")

publicclassAutoTestConfiguration{

@Bean

@ConditionalOnMissingBean

publicTestBeantestBean(TestPropertiesproperties){

System.out.println("thisisexecuted.....");

returnnewTestBean();

}

2、配置類TestProperties

@ConfigurationProperties(prefix="test")

publicclassTestProperties{

privatebooleanenable=true;

publicbooleanisEnable(){

returnenable;

publicvoidsetEnable(booleanenable){

this.enable=enable;

這兩個(gè)類都在rootpackage下,可以保證能夠正常被Spring掃描到;那么問題是TestBean會(huì)不會(huì)被正常創(chuàng)建?當(dāng)然這里的結(jié)論是不會(huì)。

可能有的同學(xué)會(huì)說你的TestProperties沒有加@Configuration注解,Spring不認(rèn)識(shí)它,那真的是這樣嗎?很顯然也不是。

在排查這個(gè)問題的過程中,也有遇到其他問題,也是之前沒有遇到過的;即使Spring源碼我看過很多遍,但是仍然會(huì)有一些邊邊角角讓你意想不到的地方;下面就針對(duì)這個(gè)問題,慢慢來揭開它的面紗。

@EnableConfigurationProperties注解行為

在之前的版本中,TestProperties是有被@Configuration注解標(biāo)注的

@Configuration//可以被spring掃描

@ConfigurationProperties(prefix="test")

publicclassTestProperties{

privatebooleanenable=true;

publicbooleanisEnable(){

returnenable;

publicvoidsetEnable(booleanenable){

this.enable=enable;

常規(guī)的思路是,當(dāng)TestProperties被掃描到之后,springenv中就會(huì)有test.enable=true的k-v存在,當(dāng)執(zhí)行AutoTestConfiguration自動(dòng)配置類刷新時(shí),@ConditionalOnProperty(prefix="test",name="enable")則會(huì)生效,進(jìn)而TestBean被正常創(chuàng)建。

但事實(shí)并非如此,下面是對(duì)于此問題的驗(yàn)證

配置有效,AutoTestConfiguration未刷新

兩個(gè)點(diǎn):

AutoTestConfiguration#testBean執(zhí)行會(huì)輸出一個(gè)log(用于判斷AutoTestConfiguration是否正常刷新)

監(jiān)聽ApplicationReadyEvent事件,拿test.enable值(用于判端配置是否正常加載,也就是TestProperties是否被正常刷新)

代碼如下:

@SpringBootApplication

publicclassApplicationimplementsApplicationListenerApplicationReadyEvent{

@Autowired

privateApplicationContextapplicationContext;

publicstaticvoidmain(String[]args){

SpringApplication.run(Application.class,args);

@Override

publicvoidonApplicationEvent(ApplicationReadyEventevent){

System.out.println(this.applicationContext.getEnvironment().getProperty("test.enable")+"------");

執(zhí)行得到的結(jié)果是AutoTestConfiguration#testBean沒有被執(zhí)行,但test.enable為true。

這里說明TestProperties是有被刷新的,但是并沒有對(duì)@ConditionalOnProperty起到作用,那么這里基本可以猜到是自動(dòng)配置類上的@ConditionalOnProperty和@EnableConfigurationProperties的作用順序問題。

在驗(yàn)證順序問題之前,我嘗試在perties中增加如下配置,rerun項(xiàng)目:

test.enable=true

到這里我得到了另一個(gè)bean沖突的問題。

prefix-type

異常提示如下:

Parameter0ofmethodtestBeanincom.glmapper.bridge.boot.config.AutoTestConfigurationrequiredasinglebean,but2werefound:

-testProperties:definedinfile[/Users/glmapper/Documents/project/exception-guides/target/classes/com/glmapper/bridge/boot/config/TestProperties.class]

-test-com.glmapper.bridge.boot.config.TestProperties:definedinnull

這里出現(xiàn)了test-com.glmapper.bridge.boot.config.TestProperties這個(gè)name的bean。我嘗試在代碼中去檢查是否有顯示給定這個(gè)bean名字,但是沒有找到,那只有一種可能,就是這個(gè)是被spring自己創(chuàng)建的。

這個(gè)過程在spring刷新階段非??壳埃谂挪檫@個(gè)問題時(shí),還是耽誤了一些時(shí)間,最后還是把問題定位一致前置到beandefinitions初始化才找到。

這里是@EnableConfigurationProperties注解的一個(gè)行為,依賴EnableConfigurationPropertiesRegistrar,源碼如下:

classEnableConfigurationPropertiesRegistrarimplementsImportBeanDefinitionRegistrar{

.getQualifiedAttributeName(EnableConfigurationPropertiesRegistrar.class,"methodValidationExcludeFilter");

@Override

publicvoidregisterBeanDefinitions(AnnotationMetadatametadata,BeanDefinitionRegistryregistry){

registerInfrastructureBeans(registry);

registerMethodValidationExcludeFilter(registry);

ConfigurationPropertiesBeanRegistrarbeanRegistrar=newConfigurationPropertiesBeanRegistrar(registry);

//toregister

getTypes(metadata).forEach(beanRegistrar::register);

通過代碼比較容易看出,EnableConfigurationPropertiesRegistrar會(huì)將目標(biāo)metadata注冊(cè)成bean;繼續(xù)debug,找到了產(chǎn)生prefix-type格式name的bean。

下面是getName的具體代碼

privateStringgetName(Classtype,MergedAnnotationConfigurationPropertiesannotation){

//拿prefix

Stringprefix=annotation.isPresent()annotation.getString("prefix"):"";

//prefix+"-"+類全限定名

return(StringUtils.hasText(prefix)prefix+"-"+type.getName():type.getName());

到這里我們先明確一個(gè)問題:

如果你使用@EnableConfigurationProperties來開啟配置類,那么就不要在配置類上使用@Configuration等能夠被Springscan識(shí)別到的注解,以免在后續(xù)的使用中同一類型的bean多個(gè)實(shí)例

@ConditionalOnProperty

在回到配置不生效問題上來,這里在官方issue是有記錄的:/spring-proj…

不過這里還是通過分析代碼來還原下問題產(chǎn)生的根本原因;這里主要從兩個(gè)方面來分析:

@ConditionalOnPropertymatch值邏輯,需要明確在匹配value時(shí),從哪些PropertySource讀取的。

@ConditionalOnPropertymatch失敗和bean刷新的邏輯

@ConditionalOnPropertymatch邏輯

首先是@ConditionalOnProperty在執(zhí)行計(jì)算時(shí),匹配value的值來源問題,通過debug代碼很容易就得到了所有的source來源,如下圖:

從debug看,本案例有4個(gè)來源(具體如上圖),實(shí)際上從源碼來看,source涵蓋了springenv所有來源:

[ConfigurationPropertySourcesPropertySource{name='configurationProperties'},

StubPropertySource{name='servletConfigInitParams'},

StubPropertySource{name='servletContextInitParams'},

PropertiesPropertySource{name='systemProperties'},OriginAwareSystemEnvironmentPropertySource{name='systemEnvironment'},

RandomValuePropertySource{name='random'},

OriginTrackedMapPropertySource{name='Configresource'classpathresource[perties]'vialocation'optional:classpath:/''}]

所以本文案例中不生效原因就是上面這些PropertySource都沒有test.enable,也就是TestProperties沒被刷新,或者其在自動(dòng)配置類之后才刷新。

@ConditionalOnPropertyskip邏輯

這里主要解釋@ConditionalOnPropert和bean被刷新的邏輯關(guān)系,具體實(shí)現(xiàn)在ConditionEvaluator類中

publicbooleanshouldSkip(@NullableAnnotatedTypeMetadatametadata,@NullableConfigur

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論