1. Bean 注入失敗問題匯總

        共 5976字,需瀏覽 12分鐘

         ·

        2023-03-11 05:05

        程序員的成長(zhǎng)之路
        互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享 
        關(guān)注


        閱讀本文大概需要 5 分鐘。

        來(lái)自:blog.csdn.net/qq_51439643/article/details/124781526

        目錄

        • 錯(cuò)誤案例
          • 常見情況一:bean 沒有被掃描
          • 常見情況二:多模塊架構(gòu) bean 沒有被掃描
          • 常見情況三:使用@Qualifier 或 @Resource 注入時(shí)指定的 name 不存在
          • 常見情況四:在攔截器或過濾器或監(jiān)聽器中注入 bean
        • 使用 IDEA 工具查看 IOC 容器

        錯(cuò)誤案例

        常見情況一:bean 沒有被掃描

        常見問題
        SpringBoot項(xiàng)目啟動(dòng)時(shí),會(huì)默認(rèn)自動(dòng)掃描啟動(dòng)類所在的包以及子包下的Bean。
        例如下面的這種情況:
        項(xiàng)目希望在 com.training 包下放置主函數(shù)與服務(wù)代碼,在 com.utils 包下放置一些配置與工具類。
        因?yàn)閱?dòng)類所在的包是:com.training,所以在com.training包與其子包下的 Bean 會(huì)被默認(rèn)自動(dòng)掃描加入到 Spring 容器中。
        而 com.utils 包不包含在默認(rèn)掃描的包之內(nèi),就算是將 bean1 對(duì)象使用注解嘗試注入容器,Spring 也不會(huì)掃描到該類,因此這是大部分 bean 注入失敗的原因。
        解決方法
        Spring 默認(rèn)掃描的是啟動(dòng)類所在的包,為了將 com.utils 包加入到掃描中,可以使用 @ComponentScan 指定額外的掃描包,配置如下:

        package com.training;

        import org.mybatis.spring.annotation.MapperScan;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.boot.context.properties.EnableConfigurationProperties;
        import org.springframework.context.ConfigurableApplicationContext;
        import org.springframework.context.annotation.ComponentScan;

        @SpringBootApplication
        // 將com.utils 包加入到 Spring 掃描范圍中
        @ComponentScan(basePackages = {"com.training","com.utils"})
        @MapperScan(basePackages = "com.training.dao")
        public class MusicMainClass {
        public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(MusicMainClass.classargs);
        }
        }

        需要注意的是:指定 @ComponetScan 后默認(rèn)的掃描位置會(huì)發(fā)生改變,因此添加新的掃描包后要確保啟動(dòng)類所在的包也能被掃描到!
        不僅僅可以使用 @ComponentScan 進(jìn)行配置,@SpringBootApplication 中的 scanBasePackages 屬性指定也能起到同樣的作用,配置方式如下:

        package com.training;

        import org.mybatis.spring.annotation.MapperScan;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.boot.context.properties.EnableConfigurationProperties;
        import org.springframework.context.ConfigurableApplicationContext;
        import org.springframework.context.annotation.ComponentScan;

        // 使用 scanBasePackages 屬性同樣能夠?qū)崿F(xiàn)
        @SpringBootApplication(scanBasePackages = {"com.training","com.utils"})
        @MapperScan(basePackages = "com.training.dao")
        public class MusicMainClass {
        public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(MusicMainClass.classargs);
        }
        }

        常見情況二:多模塊架構(gòu) bean 沒有被掃描

        常見問題
        多模塊架構(gòu)中 bean 無(wú)法注入常見問題與情況一相同,都是忽略了 SpringBoot 默認(rèn)掃描啟動(dòng)類所在包下的 bean。
        例如如下的架構(gòu):
        因?yàn)樽幽K中包路徑為 com.common.* ,而啟動(dòng)類所在的包路徑為:com.training.* ,因此子模塊中的 bean 無(wú)法被 Spring 自動(dòng)掃描到。
        解決方法
        與情況一同理,指定 @ComponentScan 或 ScanbasePackages 屬性,這里不過多贅述。

        常見情況三:使用@Qualifier 或 @Resource 注入時(shí)指定的 name 不存在

        bean名稱默認(rèn)規(guī)則
        使用 Spring 的注解 @Component、@Repository@Service、@Controller 去把一個(gè)類配置為bean時(shí),如果不指定bean的名稱,那么 bean 的名稱的默認(rèn)規(guī)則是:
        • 類名的首字母小寫,例如:類名稱 UserDao ,那么默認(rèn)的bean名稱 userDao

        • 如果類名前兩個(gè)(或兩個(gè)以上)連續(xù)的字母都是大寫,那么默認(rèn)的bean名稱與類名一樣,例如:類名稱 MIXDao ,那么默認(rèn)的bean名稱 MIXDao

        使用 SpringBoot 的注解 @Bean + @Configuration 注入 bean 時(shí),如果不指定 bean 的名稱,那么 bean 的名稱默認(rèn)規(guī)則是:bean 名稱與注入的方法名同名
        簡(jiǎn)述@Qualifer注解
        @Autowired 注解能夠自動(dòng)注入同類型的 bean,但如果與該屬性同類型的 bean 不止一個(gè)存在時(shí),Spring 無(wú)法判斷具體注入哪個(gè) bean ,@Qualifer 注解就能夠解決這樣的歧義。
        @Qualifer 能夠指定 value 字段指定需要注入 bean 的名稱,通過指定名稱來(lái)指定 Spring 到底應(yīng)該注入哪一個(gè) bean ,這樣就能消除歧義,例如下面的例子:

        public class Teacher{    
        @Autowired    
        private Student student;

        定義一個(gè)對(duì)象 Teacher 其中包含一個(gè) Student 字段的對(duì)象

        <bean id="teacher" class="com.test.Teacher"/>

        # 下面有兩個(gè)相同類型不同 name 的 Student bean
        <bean id="student1"class="com.test.Student">
        <property name="name"value="zhangsan"/>
        </bean>

        <bean id="student2"class="com.test.Student">
        <property name="name"value="lisi"/>
        </bean>

        在 xml 文件中配置上述 bean ,此時(shí)如果直接注入 Student 那么程序就會(huì)報(bào)錯(cuò),因?yàn)?nbsp;@Autowired 注解產(chǎn)生了歧義,因此需要使用 @Qualifer 注解消除歧義:

        public class Teacher{    
        @Qualifer(value = "student1")
        @Autowired    
        private Student student;

        簡(jiǎn)述 @Resource 注解
        @Resource 注解默認(rèn)通過 名稱 進(jìn)行注入,名稱可以通過 name 屬性進(jìn)行指定,如果沒有指定name屬性,當(dāng)注解寫在字段上時(shí),默認(rèn)取字段名進(jìn)行安裝名稱查找,如果注解寫在setter方法上默認(rèn)取屬性名進(jìn)行裝配。當(dāng)找不到與名稱匹配的bean時(shí)才按照類型進(jìn)行裝配。
        但是需要注意的是,如果name屬性一旦指定,就只會(huì)按照名稱進(jìn)行裝配。
        常見問題
        知道了 bean 的默認(rèn)命名規(guī)則與指定名稱的兩個(gè)注入注解后,可以試著查看注入的 bean 是否出現(xiàn)歧義,如果出現(xiàn)可以使用 @Qualifer 注解進(jìn)行限定。
        同時(shí)使用上述的兩個(gè)注解之前,需要確保 IOC 容器中存在指定的 bean ,如果沒有相應(yīng)的 bean 也會(huì)出現(xiàn)注入失敗的情況!

        常見情況四:在攔截器或過濾器或監(jiān)聽器中注入 bean

        叨叨兩句
        這兩天在寫項(xiàng)目,這個(gè)問題也是困擾了我很久很久(十幾個(gè)小時(shí)至少)。
        在項(xiàng)目中需要集成 SpringBoot + SpringSecurity 做認(rèn)證授權(quán)處理,確定注入的 bean 能夠被 Spring 掃描到,同時(shí)在 Controller、Service 層的注入也沒有問題,但是在用戶授權(quán)過濾器 UsernamePasswordAuthenticationFilter 中死活就是注入不了 bean。
        開始查閱了大量的博客資料也根本沒有往過濾器這方面來(lái)思考,在不斷地折磨后最終還是找到了問題的所在。
        常見問題
        在 WebMVC 框架中,各個(gè)元素的加載是有一定順序的,這個(gè)順序按照:

        context-param–>listener–>filter–>servlet --> … -> Bean 的實(shí)例化

        而攔截器是在Spring MVC中配置的,如果從整個(gè)項(xiàng)目中看,一個(gè)servlet請(qǐng)求的執(zhí)行過程就變成了這樣:

        context-param–>listener–>filter–>servlet–>interceptor(指的是攔截器) --> … -> Bean 的實(shí)例化

        因此上述元素中注入 bean 時(shí),bean 對(duì)象的實(shí)例化還沒有開始,因此注入的值永遠(yuǎn)為 null 值!
        解決方法
        上述對(duì)象時(shí),使用實(shí)例化的方式配置或是將需要注入的對(duì)象注入配置類中,在配置類中使用構(gòu)造函數(shù)實(shí)例化對(duì)象,例如下面的方式:
        使用構(gòu)造函數(shù):
        將需要注入的對(duì)象在配置類中注入,并將其傳入構(gòu)造函數(shù)參數(shù)進(jìn)行實(shí)例化:

        使用 IDEA 工具查看 IOC 容器

        眾所周知 idea 作為 java 程序員的一大利器,其功能相當(dāng)?shù)膹?qiáng)大,今天也是在苦惱于 bean 注入失敗原因時(shí),發(fā)現(xiàn)了IDEA支持查看 IOC 容器的功能,有了這一功能以后再遇上 bean 注入失敗時(shí)就能夠更快地找到失敗原因了!
        使用
        當(dāng)啟動(dòng) SpringBoot 項(xiàng)目后點(diǎn)擊下方的 Run 按鈕(Debug 啟動(dòng)方式點(diǎn)擊 Debug 按鈕):
        點(diǎn)擊 Console 欄上方的 Actuator :
        進(jìn)入下面的頁(yè)面后點(diǎn)擊 Beans 與 Application :
        可以看到右方出現(xiàn)了 IOC 容器中的所有 bean 數(shù)據(jù)信息:
        有了這一利器就再也不怕 bean 無(wú)法注入的問題了!
        <END>

        推薦閱讀:

        Jenkins+Docker 實(shí)現(xiàn)一鍵自動(dòng)化部署項(xiàng)目!步驟齊全,少走坑路

        終于搞懂了 @Configuration 和 @Component 的區(qū)別

        互聯(lián)網(wǎng)初中高級(jí)大廠面試題(9個(gè)G)

        內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬(wàn)并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper......等技術(shù)棧!

        ?戳閱讀原文領(lǐng)?。?/span>                                  朕已閱 

        瀏覽 38
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 欧美人禽猛交免费观看 | 久久久久久三级 | 人妖炮机调教前列腺高潮 | 攻受男男肉不打码视频免费 | 狠狠地2021最新版本 |