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

基于Spring框架由ConditionalOnMissingBean注解引發(fā)的問(wèn)題

 更新時(shí)間:2023年11月27日 10:39:30   作者:愛(ài)藝欣聊編程  
這篇文章主要介紹了基于Spring框架由ConditionalOnMissingBean注解引發(fā)的問(wèn)題,具有很好

問(wèn)題描述

最新負(fù)責(zé)的工程在做dubbo配置disconf靜態(tài)配置托管優(yōu)化,由一個(gè)StaticConfigPropertiesFactoryBean來(lái)讀取靜態(tài)配置,它是PropertiesFactoryBean的一個(gè)子類,讀取到的所有配置放在一個(gè)Properties中。

dubbo配置直接引用這個(gè)Properties的值。

像下面這樣,dubbo接口的group通過(guò)disconf的靜態(tài)配置項(xiàng)dubbo.hst.pay.group定義:

工程使用Spring Boot框架,Spring版本號(hào)4.1.1,Spring Boot版本號(hào)1.1.9,spring-security版本號(hào)4.0.2,啟用了Spring Boot框架的Anto Configuration特性。

StaticConfigPropertiesFactoryBean這個(gè)bean的configSrc屬性值是個(gè)占位符,值在外部配置文件定義。

但是啟動(dòng)工程時(shí)出現(xiàn)了一個(gè)問(wèn)題,拋出了一個(gè)IllegalArgumentException異常,異常日志如下:

Caused by: java.lang.IllegalArgumentException: configSrc error : ${disconf.configSrc}
    at com.baidu.disconf.client.haitao.properties.StaticConfigPropertiesFactoryBean.createProperties(StaticConfigPropertiesFactoryBean.java:65)
    at org.springframework.beans.factory.config.PropertiesFactoryBean.afterPropertiesSet(PropertiesFactoryBean.java:71)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
    ... 35 more

排查過(guò)程

從日志中看到configSrc這個(gè)屬性的值不滿足條件導(dǎo)致拋出了這個(gè)異常,而且值是${disconf.configSrc},這里比較奇怪,在初始化bean的時(shí)候框架不是會(huì)對(duì)占位符進(jìn)行解析求職處理的么,什么原因?qū)е抡嘉环幢惶幚韇ean就開(kāi)始初始化了?

我們知道Spring框架由PropertySourcesPlaceholderConfigurer來(lái)處理占位符,PropertySourcesPlaceholderConfigurer是一個(gè)BeanFactoryPostProcessor,在容器所有BeanDefinition被加載之后,bean初始化之前,BeanFactoryPostProcessor會(huì)被激活,PropertySourcesPlaceholderConfigurer會(huì)加載所有被引入的屬性文件,并且查找占位符對(duì)應(yīng)的值,并把對(duì)應(yīng)的值設(shè)置到bean屬性對(duì)應(yīng)的PropertyValue中,這樣在bean初始化時(shí)設(shè)置每個(gè)屬性的值時(shí)設(shè)置的就是處理后的值了。

org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, List)

就是這在觸發(fā)這個(gè)BeanFactoryPostProcessor的,注意代碼行數(shù)是162行。

但是現(xiàn)在的現(xiàn)象是configSrc這個(gè)屬性初始化之后卻是未處理的占位符字符串。

分析原因有兩種可能,第一種disconf.configSrc這個(gè)配置項(xiàng)在文件中未定義或未被容器加載,第二種StaticConfigPropertiesFactoryBean在屬性占位符處理之前就初始化了。

第一種原因很容易就排除了,disconf.configSrc這個(gè)配置項(xiàng)已經(jīng)定義了,在這次修改之前就已存在之前一直都是沒(méi)問(wèn)題的,且由于ignoreUnresolvablePlaceholders這個(gè)設(shè)置默認(rèn)是false,就算它未被定義容器也會(huì)提前拋出IllegalArgumentException異常:

org.springframework.util.PropertyPlaceholderHelper.parseStringValue(String, PlaceholderResolver, Set)

所以只能是第二種原因了,那就是StaticConfigPropertiesFactoryBean在屬性占位符處理之前就被容器初始化了。Spring框架如此龐大,要找原因最有效的手段就是debug了,把斷點(diǎn)打到StaticConfigPropertiesFactoryBean初始化代碼處,看它是從哪進(jìn)來(lái)的:

org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, List)

通過(guò)debug發(fā)現(xiàn),這個(gè)bean的初始化也是從BeanFactoryPostProcessor調(diào)進(jìn)去的,而且看下代碼是94行,在占位符處理的164行前面,好了,這里可以解釋configSrc值為什么是錯(cuò)的。

但是這些BeanFactoryPostProcessor是干嘛的?為什么在其它BFPP激活之前就去初始化bean了。

看一下這個(gè)BFPP是什么:

這個(gè)BFPP是ConfigurationClassPostProcessor,當(dāng)應(yīng)用使用了annotation-config或component-scan掃描注解bean時(shí),容器會(huì)自動(dòng)注冊(cè)一個(gè)ConfigurationClassPostProcessor來(lái)加載注解定義的BeanDefinition,按常理,這個(gè)BFPP也只會(huì)生成BeanDefinition,不會(huì)執(zhí)行bean初始化動(dòng)作。

那么是什么地方導(dǎo)致bean發(fā)生初始化了呢?

再看下上面哪個(gè)調(diào)用棧,在OnMissingBeanCondition.matches之后就調(diào)用BeanFactory的getBeansXXX了,然后一步一步觸發(fā)了createBean。

那這個(gè)OnMissingBeanCondition從哪來(lái)的呢?

從debug的情況來(lái)看跟WebMvcSecurityConfiguration有關(guān)。

看下WebMvcSecurityConfiguration這個(gè)類,它有一個(gè)@ConditionalOnMissingBean注解,這個(gè)注解作用在bean定義上,它的作用就是在容器加載它作用的bean時(shí),檢查容器中是否存在目標(biāo)類型(ConditionalOnMissingBean注解的value值)的bean了,如果存在這跳過(guò)原始bean的BeanDefinition加載動(dòng)作。

上面說(shuō)的那段邏輯就是由OnMissingBeanCondition.matches來(lái)完成的。

也就是說(shuō)上面那整棵調(diào)用樹(shù)所做的事情就是檢查容器知否已存在RequestDataValueProcessor類型的bean,如果存在則不再重復(fù)重新加載這個(gè)RequestDataValueProcessor,如果是普通的bean那還好辦直接比較bean的類型是否是RequestDataValueProcessor類型就行了,不必去初始化整個(gè)bean,但是如果是FactoryBean那就壞事了,因?yàn)镕actoryBean類型的bean最終創(chuàng)建的bean的類型并不是FactoryBean本身的類型,而是由它的getObject返回值來(lái)決定的,所以要拿到bean類型,會(huì)調(diào)它的getObject方法創(chuàng)建bean之后再比較類型。

而dubbo消費(fèi)者bean的類型都是com.alibaba.dubbo.config.spring.ReferenceBean,這恰恰是一個(gè)FactoryBean,此時(shí)會(huì)初始化消費(fèi)者bean,設(shè)置group屬性時(shí)接著初始化引用的的disconfPropertiesReader bean,所以就導(dǎo)致了悲劇。

org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch

最后只剩下最后一個(gè)問(wèn)題,WebMvcSecurityConfiguration是從哪來(lái)的,搜索代碼,直接宣布結(jié)果:

由于工程使用了AutoConfiguration特性,框架查找并讀取所有名稱是*AutoConfiguration的類,所以會(huì)找到SecurityAutoConfiguration。

這個(gè)類定義了@Configuration注解,所以會(huì)加載這個(gè)類中定義的bean,發(fā)現(xiàn)了@Import注解,根據(jù)這個(gè)標(biāo)簽讀取到并解析SpringBootWebSecurityConfiguration,繼續(xù)讀取到它的內(nèi)部類WebMvcSecurityConfigurationConditions,再讀取到內(nèi)部類的內(nèi)部類DefaultWebMvcSecurityConfiguration,這個(gè)內(nèi)部類上有@EnableWebMvcSecurity注解,這個(gè)注解又@Import了WebMvcSecurityConfiguration,這個(gè)類有@EnableWebSecurity注解,注解@Import了SpringWebMvcImportSelector,這個(gè)ImportSelector會(huì)導(dǎo)入org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration:

總結(jié)產(chǎn)生問(wèn)題的最終原因:

是因?yàn)楣こ淌褂昧薙pring Boot的Auto Configuration功能,而根據(jù)這個(gè)工程的特點(diǎn)會(huì)自動(dòng)加載安全配置SecurityAutoConfiguration,由此經(jīng)過(guò)一系列的直接或間接的import,會(huì)導(dǎo)致框架讀取WebMvcSecurityConfiguration,而這個(gè)配置在加載RequestDataValueProcessor這個(gè)bean定義的時(shí)候由于有@ConditionalOnMissingBean的作用導(dǎo)致框架會(huì)檢查容器中是否已經(jīng)存在了RequestDataValueProcessor類型的bean實(shí)例,在檢查的過(guò)程中當(dāng)掃描到sendCouponRemoteApiImpl這個(gè)dubbo消費(fèi)者bean時(shí),由于它是一個(gè)FactoryBean,getObject方法會(huì)被調(diào)用進(jìn)而執(zhí)行了bean的初始化動(dòng)作,而由于此時(shí)由于處理屬性占位符的PropertySourcesPlaceholderConfigurer還未被激活,所以導(dǎo)致bean的屬性值沒(méi)有被正確初始化。

解決方案

治標(biāo)的方案,考慮到工程主要是提供dubbo服務(wù)無(wú)需啟用安全配置,可以禁調(diào)安全配置的自動(dòng)加載,@EnableAutoConfiguration注解有exclude屬性,通過(guò)它可以禁用對(duì)SecurityAutoConfiguration的自動(dòng)加載:

治本的方案,spring社區(qū)也有人提出了相同的問(wèn)題:https://jira.spring.io/browse/SEC-3063,已確定是spring的bug,官方已在spring-security-config的4.1.0版本解決了這個(gè)問(wèn)題,刪掉了

ConditionalOnMissingBean這個(gè)注解,看代碼WebMvcSecurityConfiguration也不再使用這個(gè)注解了,升級(jí)spring-security-config到4.1.0解決問(wèn)題:

總結(jié)

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

相關(guān)文章

  • Java實(shí)現(xiàn)帶頭結(jié)點(diǎn)的單鏈表

    Java實(shí)現(xiàn)帶頭結(jié)點(diǎn)的單鏈表

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)帶頭結(jié)點(diǎn)的單鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • Spring中Bean命名的方式總結(jié)

    Spring中Bean命名的方式總結(jié)

    在?Spring?框架中,每個(gè)?bean?必須至少有一個(gè)唯一的名稱,這篇文章主要為大家詳細(xì)介紹了Spring中Bean命名的各種方式,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • Lombok @Builder注解的兩大陷阱分析及解決

    Lombok @Builder注解的兩大陷阱分析及解決

    Lombok的@Builder注解簡(jiǎn)化了建造者模式的代碼編寫,但存在兩個(gè)陷阱:無(wú)參構(gòu)造函數(shù)消失和字段默認(rèn)值失效,通過(guò)顯式聲明構(gòu)造器和使用@Builder.Default注解,可以解決這些問(wèn)題
    2026-01-01
  • SpringCloud-feign使用詳解

    SpringCloud-feign使用詳解

    Feign是Spring?Cloud中的輕量級(jí)RESTful?HTTP服務(wù)客戶端,它通過(guò)定義接口和注解簡(jiǎn)化了服務(wù)調(diào)用,Feign支持Ribbon進(jìn)行負(fù)載均衡,并且可以通過(guò)OpenFeign與Spring?MVC注解結(jié)合使用,文章詳細(xì)介紹了Feign的使用方法、自定義配置以及與其他組件的集成
    2025-01-01
  • 簡(jiǎn)單了解Spring Cloud搭建Config過(guò)程實(shí)例

    簡(jiǎn)單了解Spring Cloud搭建Config過(guò)程實(shí)例

    這篇文章主要介紹了簡(jiǎn)單了解Spring Cloud搭建Config過(guò)程實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Mybatis分頁(yè)插件使用方法詳解

    Mybatis分頁(yè)插件使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Mybatis分頁(yè)插件的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Spring Boot中RedisTemplate的使用示例詳解

    Spring Boot中RedisTemplate的使用示例詳解

    RedisTemplate.opsForHash()是RedisTemplate類提供的用于操作Hash類型的方法,它可以用于對(duì)Redis中的Hash數(shù)據(jù)結(jié)構(gòu)進(jìn)行各種操作,如設(shè)置字段值、獲取字段值、刪除字段值等,本文介紹Spring Boot中RedisTemplate的使用,感興趣的朋友一起看看吧
    2023-10-10
  • 超詳細(xì)講解Java秒殺項(xiàng)目登陸模塊的實(shí)現(xiàn)

    超詳細(xì)講解Java秒殺項(xiàng)目登陸模塊的實(shí)現(xiàn)

    這是一個(gè)主要使用java開(kāi)發(fā)的秒殺系統(tǒng),項(xiàng)目比較大,所以本篇只實(shí)現(xiàn)了登陸模塊,代碼非常詳盡,感興趣的朋友快來(lái)看看
    2022-03-03
  • idea 多模塊項(xiàng)目依賴父工程class找不到問(wèn)題的方法

    idea 多模塊項(xiàng)目依賴父工程class找不到問(wèn)題的方法

    這篇文章主要介紹了idea 多模塊項(xiàng)目依賴父工程class找不到問(wèn)題的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • Mybatis插入語(yǔ)句默認(rèn)值不生效的問(wèn)題及解決

    Mybatis插入語(yǔ)句默認(rèn)值不生效的問(wèn)題及解決

    這篇文章主要介紹了Mybatis插入語(yǔ)句默認(rèn)值不生效的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07

最新評(píng)論

遵义市| 东乡族自治县| 福建省| 黄浦区| 拉孜县| 峨眉山市| 新平| 凉城县| 徐汇区| 河东区| 铜陵市| 民丰县| 建昌县| 靖西县| 雷州市| 侯马市| 迁西县| 沈阳市| 开原市| 离岛区| 丰原市| 宁强县| 龙胜| 伊金霍洛旗| 邹城市| 富源县| 大田县| 关岭| 马龙县| 睢宁县| 慈利县| 谷城县| 景谷| 剑河县| 吉林市| 阳春市| 区。| 湘阴县| 武夷山市| 安顺市| 托里县|