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

SpringBoot 自動配置失效的解決方法

 更新時間:2021年11月17日 15:53:02   作者:glmapper  
本文主要介紹了SpringBoot 自動配置失效的解決方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

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

問題描述

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

1、自動配置類:AutoTestConfiguration

@Configuration
@EnableConfigurationProperties(TestProperties.class)
@ConditionalOnProperty(prefix = "test", name = "enable")
public class AutoTestConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public TestBean testBean(TestProperties properties){
        System.out.println("this is executed.....");
        return new TestBean();
    }
}

2、配置類 TestProperties

@ConfigurationProperties(prefix = "test")
public class TestProperties {
    private boolean enable = true;
    public boolean isEnable() {
        return enable;
    }
    public void setEnable(boolean enable) {
        this.enable = enable;
    }
}

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

可能有的同學(xué)會說你的 TestProperties 沒有加 @Configuration 注解,Spring 不認(rèn)識它,那真的是這樣嗎?很顯然也不是。
在排查這個問題的過程中,也有遇到其他問題,也是之前沒有遇到過的;即使 Spring 源碼我看過很多遍,但是仍然會有一些邊邊角角讓你意想不到的地方;下面就針對這個問題,慢慢來揭開它的面紗。

@EnableConfigurationProperties 注解行為

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

@Configuration // 可以被 spring 掃描
@ConfigurationProperties(prefix = "test")
public class TestProperties {
    private boolean enable = true;
    public boolean isEnable() {
        return enable;
    }
    public void setEnable(boolean enable) {
        this.enable = enable;
    }
}

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

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

配置有效,AutoTestConfiguration 未刷新

兩個點(diǎn):

  • AutoTestConfiguration#testBean 執(zhí)行會輸出一個 log(用于判斷 AutoTestConfiguration 是否正常刷新)
  • 監(jiān)聽 ApplicationReadyEvent 事件,拿 test.enable 值(用于判端配置是否正常加載,也就是 TestProperties 是否被正常刷新)

代碼如下:

@SpringBootApplication
public class Application implements ApplicationListener<ApplicationReadyEvent> {
   @Autowired
   private ApplicationContext applicationContext;
   public static void main(String[] args) {
      SpringApplication.run(Application.class, args);
   }
   @Override
   public void onApplicationEvent(ApplicationReadyEvent event) {
      System.out.println(this.applicationContext.getEnvironment().getProperty("test.enable")  + "------");
   }
}

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

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

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

test.enable=true

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

prefix-type

異常提示如下:

Parameter 0 of method testBean in com.glmapper.bridge.boot.config.AutoTestConfiguration required a single bean, but 2 were found:
 - testProperties: defined in file [/Users/glmapper/Documents/project/exception-guides/target/classes/com/glmapper/bridge/boot/config/TestProperties.class]
 - test-com.glmapper.bridge.boot.config.TestProperties: defined in null

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

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

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

class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {
         .getQualifiedAttributeName(EnableConfigurationPropertiesRegistrar.class, "methodValidationExcludeFilter");

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
      registerInfrastructureBeans(registry);
      registerMethodValidationExcludeFilter(registry);
      ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
      // to register
      getTypes(metadata).forEach(beanRegistrar::register);
   }

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

下面是 getName 的具體代碼

private String getName(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {
    // 拿 prefix
   String prefix = annotation.isPresent() ? annotation.getString("prefix") : "";
   // prefix + "-" + 類全限定名 
   return (StringUtils.hasText(prefix) ? prefix + "-" + type.getName() : type.getName());
}

到這里我們先明確一個問題:

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

@ConditionalOnProperty

在回到配置不生效問題上來,這里在官方 issue 是有記錄的:github.com/spring-proj…
不過這里還是通過分析代碼來還原下問題產(chǎn)生的根本原因;這里主要從兩個方面來分析:

  • @ConditionalOnProperty match 值邏輯,需要明確在匹配 value 時,從哪些 PropertySource 讀取的。
  • @ConditionalOnProperty match 失敗和 bean 刷新的邏輯

@ConditionalOnProperty match 邏輯

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

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

[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, 
StubPropertySource {name='servletConfigInitParams'}, 
StubPropertySource {name='servletContextInitParams'}, 
PropertiesPropertySource {name='systemProperties'}, OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}, 
RandomValuePropertySource {name='random'}, 
OriginTrackedMapPropertySource {name='Config resource 'class path resource [application.properties]' via location 'optional:classpath:/''}]

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

@ConditionalOnProperty skip 邏輯

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

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
    // 1、沒有 Conditional 注解,則掃描時不會跳過當(dāng)前 bean
    // 2、遍歷 conditions 進(jìn)行判斷是否滿足
}

所以對于自動配置類上的注解,Conditional 是作為當(dāng)前類是否允許被刷新的前提,只有 Conditional 條件滿足,才會將當(dāng)前的自動配置類加入到待刷新 bean 列表中去,如果 Conditional 不滿足,這個 bean 將直接被跳過,不會被放到 BeandefinitonMap 中去,也就不會有后續(xù)的刷新動作。

@ConditionalOnProperty 作用時機(jī)在 BeanDefiniton 被創(chuàng)建之前,其執(zhí)行時機(jī)要比 @EnableConfigurationProperties 作用要早,這也就說明了,為什么 TestProperties 中 test.enable=true, AutoTestConfiguration 也不會刷新的原因了。

總結(jié)

本文通過一個簡單 case,對于項(xiàng)目中遇到的 SpringBoot 配置失效導(dǎo)致 bean 未被刷新問題進(jìn)行了回溯,總結(jié)如下:

Conditional 相關(guān)注解對于自動配置類來說,作用時機(jī)較早,用于決定當(dāng)前自動配置類是否允許被刷新
@EnableConfigurationProperties enable 的類,會默認(rèn)注冊一個 bean,bean 名字格式為 prefix-type

到此這篇關(guān)于SpringBoot 自動配置失效的解決方法的文章就介紹到這了,更多相關(guān)SpringBoot 自動配置失效內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java中switch case語句需要加入break的原因解析

    java中switch case語句需要加入break的原因解析

    這篇文章主要介紹了java中switch case語句需要加入break的原因解析的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • Java加解密技術(shù)系列之RSA詳解

    Java加解密技術(shù)系列之RSA詳解

    出于安全考慮,網(wǎng)絡(luò)的傳輸中經(jīng)常對傳輸數(shù)據(jù)做加密和編碼處理,本篇文章主要介紹Java加解密技術(shù)系列之RSA詳解,非常具有實(shí)用價值,需要的朋友可以參考下。
    2016-10-10
  • Java之SpringBoot定時任務(wù)案例講解

    Java之SpringBoot定時任務(wù)案例講解

    這篇文章主要介紹了Java之SpringBoot定時任務(wù)案例講解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java實(shí)現(xiàn)TopK問題的方法

    Java實(shí)現(xiàn)TopK問題的方法

    這篇文章主要介紹了Java實(shí)現(xiàn)TopK問題的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • SpringBoot整合郵件發(fā)送的四種方法

    SpringBoot整合郵件發(fā)送的四種方法

    這篇文章主要介紹了SpringBoot整合郵件發(fā)送的四種方法,SpringBoot中集成了發(fā)送郵件的功能,本文做了進(jìn)一步優(yōu)化,需要的朋友可以參考下
    2023-03-03
  • SpringBoot使用MockMvc進(jìn)行Web集成測試的示例詳解

    SpringBoot使用MockMvc進(jìn)行Web集成測試的示例詳解

    MockMvc?是一個測試框架,可以模擬?HTTP?請求和響應(yīng),在本文中,我們將介紹如何使用MockMvc進(jìn)行Web集成測試,以及如何編寫測試用例來測試Spring?MVC控制器,希望對大家有所幫助
    2023-06-06
  • WeakHashMap的使用方法詳解

    WeakHashMap的使用方法詳解

    這篇文章主要介紹了WeakHashMap的使用方法詳解的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-10-10
  • 深入剖析ArrayList的remove方法

    深入剖析ArrayList的remove方法

    這篇文章主要介紹了ArrayList的remove方法使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教。</p>
    2021-09-09
  • Intellij?IDEA如何設(shè)置代理

    Intellij?IDEA如何設(shè)置代理

    這篇文章主要介紹了Intellij?IDEA如何設(shè)置代理問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • java IO實(shí)現(xiàn)電腦搜索、刪除功能的實(shí)例

    java IO實(shí)現(xiàn)電腦搜索、刪除功能的實(shí)例

    下面小編就為大家?guī)硪黄猨ava IO實(shí)現(xiàn)電腦搜索、刪除功能的實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12

最新評論

乌海市| 静乐县| 沙田区| 白城市| 桐城市| 景谷| 宝鸡市| 常熟市| 黔西| 滕州市| 宁乡县| 万源市| 卫辉市| 略阳县| 金山区| 瓦房店市| 中卫市| 磐安县| 新巴尔虎右旗| 和田县| 三都| 云梦县| 屏东市| 全南县| 鸡西市| 龙南县| 沈丘县| 德安县| 丁青县| 平乐县| 泽州县| 永善县| 西青区| 九龙城区| 息烽县| 大田县| 盐津县| 哈尔滨市| 淄博市| 互助| 辽阳县|