感謝邀請!
1、首先我們看下@Autowired和@Resource的用法
@Autowired的用法
@Autowired是Spring自帶的注解,位于包
org.springframework.beans.factory.annotation
下1、自動注入
1、自動裝配可以按照類型進行裝配,如果在IOC容器發現多個相同類型的組件怎么辦呢?
我們可以按照屬性名稱來進行裝配,比如存在UserDao1和UserDao2
@Autowired
privateUserDaouserDao;
我們通過@Autowied修飾屬性名稱時userDao,那么先用byType來查找,如果IOC容器中存在多個相同類型的組件,則使用userDao名稱來找,若屬性名稱為userDao2,那么就加載userDao2的組件。
2、如果我們需要需要指定特定的組件來進行裝配呢?又該怎么辦呢?
可以使用@Qualifier("userDao")來指定裝配的組件或者在配置類的@Bean上加上
@Primary注解。
@Autowired
@Qualifier("userDao")
privateUserDaouserDao2;
3、如果我們加載的時候既沒有userDao有沒有userDao2,那么裝配的時候是什么現象呢?
配置如下:
上圖初始化了兩個UserDao,Bean組件名稱為userDao3和userDao2。
再次注入的時候:
先按byType去查找,查找的時候發現有兩個UserDao類型,從而又轉換用userDao名稱查找。但是又查不到,所以報一下錯誤。
Noqualifyingbeanoftype'com.wy.study.autowired.UserDao'available:
expectedsinglematchingbeanbutfound2:userDao3,userDao2
上述的錯誤是,期望去獲取一個實例,但是卻找到了兩個。
如果不想拋出異常呢,我們需要指定required為false的時候就可以了
@Autowired(required=false)
privateUserDaouserDao;
但是上述只能保證啟動的時候不報錯,但是調用的時候還是得報錯。
4、@Autowired也可以使用在方法參數上
4、@Autowired標注在構造方法上
@Resource注解
@Resource是由J2EE體用的,需要導入包javax.annotation.Resource。
功能和@Autowired的功能差不多一樣,但是不支持@Primary和@Qualifier的支持
@Resource有兩個屬性:name和type
name:bean的名稱type:bean的類型
默認按照byName自動注入
有下面4中情況
①如果只是指定了name屬性,則從IOC容器中查找名稱為userDao的bean進行裝配,找不到則拋出異常。
@Resource(name="userDao")
privateUserDaouserDao;
②如果指定了type,則從IOC容器中查找UserDao類型的Bean,找不到或者找到多個,都會拋出異常。
③如果既沒指定name,又沒指定type,則回退為一個原始類型進行匹配,如果匹配則自動裝配;
④若兩個屬性都使用了,則需要找到唯一匹配的bean進行裝配,找不到則拋出異常。
@Autowired注解在Spring源碼中的解析
容器對Bean的自動裝配發生在容器對Bean依賴注入的過程中,在對SpringIOC容器的以阿里注入源碼分析,我們已經知道容器對bean實例對象的依賴屬性注入發生在
AbstractAutowireCapableBeanFactory類的populateBean方法。下面我們對其的解析進行說明。
1、AbstractAutowireCapableBeanFactory對Bean實例對象進行屬性依賴注入
當應用程序第一次getBean()方法時,向IOC容器索取Bean時,容器創建實例對象,并且對Bean實例對象進行屬性依賴注入,AbstractAutowireCapableBeanFactory的populateBean方法對屬性進行依賴注入
調用棧如下:
源碼解釋如下:
2、SpringIOC容器根據Bean名稱或者類型進行autowired自動屬性依賴注入
SpringIOC容器根據Bean名稱或者類型進行autowired自動屬性依賴注入的代碼如下:
從上面可以看到,通過屬性名進行自動依賴注入相比通過屬性類型進行自動依賴注入要稍微簡單一些,但是真正實現屬性注入的是DefaultSingletonBeanRegistry類的registerDependentBean方法進行注入;
解析步驟如下:
處理bean名稱,將別名轉換為規范的Bean名稱
StringcanonicalName=canonicalName(beanName);
下面是多線程同步,保證容器內的數據的一致性
在容器中通過"Bean名稱找到全部依賴Bean名稱集合“查找指定名稱Bean的依賴Bean
synchronized(this.dependentBeanMap)
(1)獲取指定名稱Bean的所有依賴Bean名稱
Set<String>dependentBeans=this.dependentBeanMap.get(canonicalName);
如果dependentBeanMap中么有,則把依賴的bean放進去
(2)將bean所依賴的Bean添加到容器的集合中
dependentBeans.add(dependentBeanName);
可以看出,autowired的實現過程如下:
①對Bean的屬性調用getBean方法,完成依賴Bean的初始化和依賴注入
②將依賴Bean的屬性引用設置到被依賴的Bean屬性上
③將依賴Bean的名稱和被依賴Bean的名稱存儲到IOC容器上
總結
1、@Resource和@Autowired都可以用來裝配bean,都可以寫在字段上或者是寫在setter方法上。
2、@Autowired默認是按照byType進行裝配的,所以默認情況下依賴的對象必須存在,如果允許為null,則可以使用required屬性為false,如果想使用byName進行裝配,那么可以和@Qualifier注解相互配合。
3、@Resource默認是按照byName進行裝配的,如果指定了name,則會查找id指定name的bean進行裝配,如果指定了type,則會從SpringIOC中找到唯一的Bean進行裝配,找不到則排除異常。
推薦使用@Resource注解在字段上,這樣就不用寫setter方法了,并且這個注解屬于J2EE的,減少了與Spring的耦合。
本文由碼農的一天撰寫,如果你認同我的觀點的話,可以點贊加關注一下;如果你對本篇文章有其他見解的話,也歡迎在下方的評論區瀏覽討論!