<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          談談 Spring 中的 NoSuchBeanDefinitionException

          共 4293字,需瀏覽 9分鐘

           ·

          2020-11-06 03:06

          作者 |?Giraffe

          來源 |?http://dwz.date/b4pu

          概述

          org.springframework.beans.factory.NoSuchBeanDefinitionException?是很常見的異常,可以說絕大多數(shù)使用過 Spring 的人都曾遇到過它。本文旨在總結(jié)下NoSuchBeanDefinitionException(以下簡稱 NSBDE)的含義,哪些情況下可能拋出 NSBDE,和如何解決(文中配置均用 JavaConfig)。

          什么是 NoSuchBeanDefinitionException

          從字面其實就很好理解,NoSuchBeanDefinitionException 就是沒有找到指定 Bean 的 Definition。NoSuchBeanDefinitionException 的 JavaDoc是這樣定義的:

          Exception thrown when a BeanFactory is asked for a bean instance for which it cannot find a definition. This may point to a non-existing bean, a non-unique bean, or a manually registered singleton instance without an associated bean definition.

          下面看看可能拋出 NSBDE 的一些情況。

          情況1: No qualifying bean of type […] found for dependency

          最常見的拋出 NSBDE 的情況就是在一個 BeanA 中注入 BeanB 時找不到 BeanB 的定義。例子如下:

          @Component
          public?class?BeanA?{
          ????@Autowired
          ????private?BeanB?dependency;
          ????//...
          }

          當在 BeanA 中注入 BeanB 時,如果在 Spring 上下文中找不到 BeanB 的定義,就會拋出 NSBDE。異常信息如下:

          org.springframework.beans.factory.NoSuchBeanDefinitionException:?
          No?qualifying?bean?of?type?[org.baeldung.packageB.BeanB]
          ??found?for?dependency:?
          ????expected?at?least?1?bean?which?qualifies?as
          ??autowire?candidate?for?this?dependency.?
          ????Dependency?annotations:?
          ??{@org.springframework.beans.factory.annotation.Autowired(required=true)}

          拋異常的原因在異常信息中說的很清楚:expected at least 1 bean which qualifies as autowire candidate for this dependency。所以要么是 BeanB 不存在在 Spring 上下文中(比如沒有標注 @ Component,@Repository,@Service, @Controller等注解) ,要么就是 BeanB 所在的包沒有被 Spring 掃描到。

          解決辦法就是先確認 BeanB 有沒有被某些注解聲明為 Bean:

          package?org.baeldung.packageB;
          @Component
          public?class?BeanB?{?...}

          如果 BeanB 已經(jīng)被聲明為一個 Bean,就再確認 BeanB 所在的包有沒有被掃描。

          @Configuration
          @ComponentScan("org.baeldung.packageB")
          public?class?ContextWithJavaConfig?{
          }

          情況2: No qualifying bean of type […] is defined

          還有一種可能拋出 NSBDE 的情況是在上下文中存在著兩個 Bean,比如有一個接口 IBeanB,它有兩個實現(xiàn)類 BeanB1 和 BeanB2。

          @Component
          public?class?BeanB1?implements?IBeanB?{
          ????//
          }
          @Component
          public?class?BeanB2?implements?IBeanB?{
          ????//
          }

          現(xiàn)在,如果 BeanA 按照下面的方式注入,那么 Spring 將不知道要注入兩個實現(xiàn)中的哪一個,就會拋出 NSBDE。

          @Component
          public?class?BeanA?{
          ????@Autowired
          ????private?IBeanB?dependency;
          }

          異常信息如下:

          Caused?by:?org.springframework.beans.factory.NoUniqueBeanDefinitionException:?
          No?qualifying?bean?of?type
          ??[org.baeldung.packageB.IBeanB]?is?defined:?
          ????expected?single?matching?bean?but?found?2:?beanB1,beanB2

          仔細看異常信息會發(fā)現(xiàn),并不是直接拋出 NSBDE,而是它的子類?NoUniqueBeanDefinitionException,這是 Spring 3.2.1 之后引入的新異常,目的就是為了和第一種找不到 Bean Definition 的情況作區(qū)分。

          解決辦法1就是利用?@Qualifier?注解,明確指定要注入的 Bean 的名字(BeanB2 默認的名字就是 beanB2)。

          @Component
          public?class?BeanA?{
          ????@Autowired
          ????@Qualifier("beanB2")
          ????private?IBeanB?dependency;
          }

          除了指定名字,我們還可以將其中一個 Bean 加上?@Primary的注解,這樣會選擇加了 Primary 注解的 Bean 來注入,而不會拋異常:

          @Component
          @Primary
          public?class?BeanB1?implements?IBeanB?{
          ????//
          }

          這樣 Spring 就能夠知道到底應該注入哪個 Bean 了。

          情況3: No Bean Named […] is defined

          NSBDE 還可能在從 Spring 上下文中通過名字獲取一個 Bean 時拋出。

          @Component
          public?class?BeanA?implements?InitializingBean?{
          ????@Autowired
          ????private?ApplicationContext?context;
          ????@Override
          ????public?void?afterPropertiesSet()?{
          ????????context.getBean("someBeanName");
          ????}
          }

          在這種情況中,如果找不到指定名字 Bean 的 Definition,就會拋出如下異常:

          Caused?by:?org.springframework.beans.factory.NoSuchBeanDefinitionException:?
          No?bean?named?'someBeanName'?is?defined

          情況4: 代理 Beans

          Spring 通過 AOP 代理?實現(xiàn)了許多高級功能,比如:

          • 通過?@Transactional完成?事務管理

          • 通過?@Cacheable實現(xiàn)緩存

          • 通過?@Async和?@Scheduled實現(xiàn)任務調(diào)度和異步執(zhí)行

          Spring 有兩種方式實現(xiàn)代理:

          1. 利用?JDK 動態(tài)代理機制?,在運行時為實現(xiàn)了某些接口的類動態(tài)創(chuàng)建一個實現(xiàn)了同樣接口的代理對象。

          2. 使用 CGLIB,CGLIB 可以在運行期擴展Java類與實現(xiàn)Java接口,也就是說當一個類沒有實現(xiàn)接口時,必須用 CGLIB 生成代理對象。

          所以,當 Spring 上下文中的一個實現(xiàn)了某個接口的 Bean 通過JDK 動態(tài)代理機制被代理時,代理類并不是繼承了目標類,而是實現(xiàn)同樣的接口。

          也正因為如此,如果一個 Bean 通過接口注入時,可以成功被注入。但如果是通過真正的類注入,那么 Spring 將無法找到匹配這個類的 Definition——因為代理類并沒有繼承這個類。

          以 Spring 中比較常見的事務管理為例,假設 ServiceA 中要注入 ServiceB,兩個 Service 均標注了?@Transactional注解來進行事務管理,那么下面的注入方式是不會正常 work 的。

          @Service
          @Transactional
          public?class?ServiceA?implements?IServiceA{
          ????@Autowired
          ????private?ServiceB?serviceB;
          ????...
          ????}
          ?
          @Service
          @Transactional
          public?class?ServiceB?implements?IServiceB{
          }

          解決辦法就是通過接口來進行注入:

          @Service
          @Transactional
          public?class?ServiceA?implements?IServiceA{
          ????@Autowired
          ????private?IServiceB?serviceB;
          ????}
          ?
          @Service
          @Transactional
          public?class?ServiceB?implements?IServiceB{
          }


          -END-


          springboot開發(fā)基礎腳手架零基礎到項目實戰(zhàn)?

          加我微信回復“springboot腳手架”即可獲取

          點個在看?

          謝謝支持喲 (*^__^*)


          瀏覽 25
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欲色视频| 黄片操| 美女操逼13P | 丰满人妻一区二区三区四区色 | 国产九色 |