激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - Java教程 - 徹底搞明白Spring中的自動裝配和Autowired注解的使用

徹底搞明白Spring中的自動裝配和Autowired注解的使用

2021-07-22 15:42清幽之地 Java教程

這篇文章主要介紹了徹底搞明白Spring中的自動裝配和Autowired注解的使用,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一、自動裝配

當spring裝配bean屬性時,有時候非常明確,就是需要將某個bean的引用裝配給指定屬性。比如,如果我們的應用上下文中只有一個org.mybatis.spring.sqlsessionfactorybean類型的bean,那么任意一個依賴sqlsessionfactorybean的其他bean就是需要這個bean。畢竟這里只有一個sqlsessionfactorybean的bean。

為了應對這種明確的裝配場景,spring提供了自動裝配(autowiring)。與其顯式的裝配bean屬性,為何不讓spring識別出可以自動裝配的場景。

當涉及到自動裝配bean的依賴關系時,spring有多種處理方式。因此,spring提供了4種自動裝配策略。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface autowirecapablebeanfactory{
 
 //無需自動裝配
 int autowire_no = 0;
 
 //按名稱自動裝配bean屬性
 int autowire_by_name = 1;
 
 //按類型自動裝配bean屬性
 int autowire_by_type = 2;
 
 //按構造器自動裝配
 int autowire_constructor = 3;
 
 //過時方法,spring3.0之后不再支持
 @deprecated
 int autowire_autodetect = 4;
}

spring在autowirecapablebeanfactory接口中定義了這幾種策略。其中,autowire_autodetect被標記為過時方法,在spring3.0之后已經不再支持。

1、byname

它的意思是,把與bean的屬性具有相同名字的其他bean自動裝配到bean的對應屬性中。聽起來可能比較拗口,我們來看個例子。

首先,在user的bean中有個屬性role myrole,再創建一個role的bean,它的名字如果叫myrole,那么在user中就可以使用byname來自動裝配。

?
1
2
3
4
5
6
7
public class user{
 private role myrole;
}
public class role {
 private string id;
 private string name;
}

上面是bean的定義,再看配置文件。

?
1
2
3
4
5
6
<bean id="myrole" class="com.viewscenes.netsupervisor.entity.role">
 <property name="id" value="1001"></property>
 <property name="name" value="管理員"></property>
</bean>
 
<bean id="user" class="com.viewscenes.netsupervisor.entity.user" autowire="byname"></bean>

如上所述,只要屬性名稱和bean的名稱可以對應,那么在user的bean中就可以使用byname來自動裝配。那么,如果屬性名稱對應不上呢?

2、bytype

是的,如果不使用屬性名稱來對應,你也可以選擇使用類型來自動裝配。它的意思是,把與bean的屬性具有相同類型的其他bean自動裝配到bean的對應屬性中。

?
1
2
3
4
5
6
<bean class="com.viewscenes.netsupervisor.entity.role">
 <property name="id" value="1001"></property>
 <property name="name" value="管理員"></property>
</bean>
 
<bean id="user" class="com.viewscenes.netsupervisor.entity.user" autowire="bytype"></bean>

還是上面的例子,如果使用bytype,role bean的id都可以省去。

3、constructor

它是說,把與bean的構造器入參具有相同類型的其他bean自動裝配到bean構造器的對應入參中。值的注意的是,具有相同類型的其他bean這句話說明它在查找入參的時候,還是通過bean的類型來確定。
構造器中入參的類型為role

?
1
2
3
4
5
6
7
8
9
public class user{
 private role role;
 
 public user(role role) {
 this.role = role;
 }
}
 
<bean id="user" class="com.viewscenes.netsupervisor.entity.user" autowire="constructor"></bean>

4、autodetect

它首先會嘗試使用constructor進行自動裝配,如果失敗再嘗試使用bytype。不過,它在spring3.0之后已經被標記為@deprecated。

5、默認自動裝配

默認情況下,default-autowire屬性被設置為none,標示所有的bean都不使用自動裝配,除非bean上配置了autowire屬性。
如果你需要為所有的bean配置相同的autowire屬性,有個辦法可以簡化這一操作。

在根元素beans上增加屬性default-autowire="bytype"。

?
1
<beans default-autowire="bytype">

spring自動裝配的優點不言而喻。但是事實上,在spring xml配置文件里的自動裝配并不推薦使用,其中筆者認為最大的缺點在于不確定性。或者除非你對整個spring應用中的所有bean的情況了如指掌,不然隨著bean的增多和關系復雜度的上升,情況可能會很糟糕

二、autowired

從spring2.5開始,開始支持使用注解來自動裝配bean的屬性。它允許更細粒度的自動裝配,我們可以選擇性的標注某一個屬性來對其應用自動裝配。

spring支持幾種不同的應用于自動裝配的注解。

  • spring自帶的@autowired注解。
  • jsr-330的@inject注解。
  • jsr-250的@resource注解。

我們今天只重點關注autowired注解,關于它的解析和注入過程,請參考筆者spring源碼系列的文章。spring源碼分析(二)bean的實例化和ioc依賴注入

使用@autowired很簡單,在需要注入的屬性加入注解即可。

?
1
2
@autowired
userservice userservice;

不過,使用它有幾個點需要注意。

1、強制性

默認情況下,它具有強制契約特性,其所標注的屬性必須是可裝配的。如果沒有bean可以裝配到autowired所標注的屬性或參數中,那么你會看到nosuchbeandefinitionexception的異常信息。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public object doresolvedependency(dependencydescriptor descriptor, string beanname,
  set<string> autowiredbeannames, typeconverter typeconverter) throws beansexception {
 
 //查找bean
 map<string, object> matchingbeans = findautowirecandidates(beanname, type, descriptor);
 //如果拿到的bean集合為空,且isrequired,就拋出異常。
 if (matchingbeans.isempty()) {
 if (descriptor.isrequired()) {
  raisenosuchbeandefinitionexception(type, "", descriptor);
 }
 return null;
 }
}

看到上面的源碼,我們可以得到這一信息,bean集合為空不要緊,關鍵isrequired條件不能成立,那么,如果我們不確定屬性是否可以裝配,可以這樣來使用autowired。

?
1
2
@autowired(required=false)
userservice userservice;

2、裝配策略

我記得曾經有個面試題是這樣問的:autowired是按照什么策略來自動裝配的呢?
關于這個問題,不能一概而論,你不能簡單的說按照類型或者按照名稱。但可以確定的一點的是,它默認是按照類型來自動裝配的,即bytype。

默認按照類型裝配

關鍵點findautowirecandidates這個方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected map<string, object> findautowirecandidates(
 string beanname, class<?> requiredtype, dependencydescriptor descriptor) {
 
 //獲取給定類型的所有bean名稱,里面實際循環所有的beanname,獲取它的實例
 //再通過istypematch方法來確定
 string[] candidatenames = beanfactoryutils.beannamesfortypeincludingancestors(
  this, requiredtype, true, descriptor.iseager());
  
 map<string, object> result = new linkedhashmap<string, object>(candidatenames.length);
 
 //根據返回的beanname,獲取其實例返回
 for (string candidatename : candidatenames) {
 if (!isselfreference(beanname, candidatename) && isautowirecandidate(candidatename, descriptor)) {
  result.put(candidatename, getbean(candidatename));
 }
 }
 return result;
}

按照名稱裝配

可以看到它返回的是一個列表,那么就表明,按照類型匹配可能會查詢到多個實例。到底應該裝配哪個實例呢?我看有的文章里說,可以加注解以此規避。比如@qulifier、@primary等,實際還有個簡單的辦法。

比如,按照userservice接口類型來裝配它的實現類。userservice接口有多個實現類,分為userserviceimpl、userserviceimpl2。那么我們在注入的時候,就可以把屬性名稱定義為bean實現類的名稱。

?
1
2
@autowired
userservice userserviceimpl2;

這樣的話,spring會按照byname來進行裝配。首先,如果查到類型的多個實例,spring已經做了判斷。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public object doresolvedependency(dependencydescriptor descriptor, string beanname,
  set<string> autowiredbeannames, typeconverter typeconverter) throws beansexception {
  
 //按照類型查找bean實例
 map<string, object> matchingbeans = findautowirecandidates(beanname, type, descriptor);
 //如果bean集合為空,且isrequired成立就拋出異常
 if (matchingbeans.isempty()) {
 if (descriptor.isrequired()) {
  raisenosuchbeandefinitionexception(type, "", descriptor);
 }
 return null;
 }
 //如果查找的bean實例大于1個
 if (matchingbeans.size() > 1) {
 //找到最合適的那個,如果沒有合適的。。也拋出異常
 string primarybeanname = determineautowirecandidate(matchingbeans, descriptor);
 if (primarybeanname == null) {
  throw new nouniquebeandefinitionexception(type, matchingbeans.keyset());
 }
 if (autowiredbeannames != null) {
  autowiredbeannames.add(primarybeanname);
 }
 return matchingbeans.get(primarybeanname);
 }
}

可以看出,如果查到多個實例,determineautowirecandidate方法就是關鍵。它來確定一個合適的bean返回。其中一部分就是按照bean的名稱來匹配。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
protected string determineautowirecandidate(map<string, object> candidatebeans,
  dependencydescriptor descriptor) {
 //循環拿到的bean集合
 for (map.entry<string, object> entry : candidatebeans.entryset()) {
 string candidatebeanname = entry.getkey();
 object beaninstance = entry.getvalue();
 //通過matchesbeanname方法來確定bean集合中的名稱是否與屬性的名稱相同
 if (matchesbeanname(candidatebeanname, descriptor.getdependencyname())) {
  return candidatebeanname;
 }
 }
 return null;
}

最后我們回到問題上,得到的答案就是:@autowired默認使用bytype來裝配屬性,如果匹配到類型的多個實例,再通過byname來確定bean。

3、主和優先級

上面我們已經看到了,通過bytype可能會找到多個實例的bean。然后再通過byname來確定一個合適的bean,如果通過名稱也確定不了呢?

還是determineautowirecandidate這個方法,它還有兩種方式來確定。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected string determineautowirecandidate(map<string, object> candidatebeans,
  dependencydescriptor descriptor) {
 class<?> requiredtype = descriptor.getdependencytype();
 //通過@primary注解來標識bean
 string primarycandidate = determineprimarycandidate(candidatebeans, requiredtype);
 if (primarycandidate != null) {
 return primarycandidate;
 }
 //通過@priority(value = 0)注解來標識bean value為優先級大小
 string prioritycandidate = determinehighestprioritycandidate(candidatebeans, requiredtype);
 if (prioritycandidate != null) {
 return prioritycandidate;
 }
 return null;
}

primary

它的作用是看bean上是否包含@primary注解,如果包含就返回。當然了,你不能把多個bean都設置為@primary,不然你會得到nouniquebeandefinitionexception這個異常。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected string determineprimarycandidate(map<string, object> candidatebeans, class<?> requiredtype) {
 string primarybeanname = null;
 for (map.entry<string, object> entry : candidatebeans.entryset()) {
 string candidatebeanname = entry.getkey();
 object beaninstance = entry.getvalue();
 if (isprimary(candidatebeanname, beaninstance)) {
  if (primarybeanname != null) {
  boolean candidatelocal = containsbeandefinition(candidatebeanname);
  boolean primarylocal = containsbeandefinition(primarybeanname);
  if (candidatelocal && primarylocal) {
   throw new nouniquebeandefinitionexception(requiredtype, candidatebeans.size(),
    "more than one 'primary' bean found among candidates: " + candidatebeans.keyset());
  }
  else if (candidatelocal) {
   primarybeanname = candidatebeanname;
  }
  }
  else {
  primarybeanname = candidatebeanname;
  }
 }
 }
 return primarybeanname;
}

priority

你也可以在bean上配置@priority注解,它有個int類型的屬性value,可以配置優先級大小。數字越小的,就被優先匹配。同樣的,你也不能把多個bean的優先級配置成相同大小的數值,否則nouniquebeandefinitionexception異常照樣出來找你。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
protected string determinehighestprioritycandidate(map<string, object> candidatebeans,
     class<?> requiredtype) {
 string highestprioritybeanname = null;
 integer highestpriority = null;
 for (map.entry<string, object> entry : candidatebeans.entryset()) {
 string candidatebeanname = entry.getkey();
 object beaninstance = entry.getvalue();
 integer candidatepriority = getpriority(beaninstance);
 if (candidatepriority != null) {
  if (highestprioritybeanname != null) {
  //如果優先級大小相同
  if (candidatepriority.equals(highestpriority)) {
   throw new nouniquebeandefinitionexception(requiredtype, candidatebeans.size(),
   "multiple beans found with the same priority ('" + highestpriority + "') " +
    "among candidates: " + candidatebeans.keyset());
  }
  else if (candidatepriority < highestpriority) {
   highestprioritybeanname = candidatebeanname;
   highestpriority = candidatepriority;
  }
  }
  else {
  highestprioritybeanname = candidatebeanname;
  highestpriority = candidatepriority;
  }
 }
 }
 return highestprioritybeanname;
}

最后,有一點需要注意。priority的包在javax.annotation.priority;,如果想使用它還要引入一個坐標。

?
1
2
3
4
5
<dependency>
 <groupid>javax.annotation</groupid>
 <artifactid>javax.annotation-api</artifactid>
 <version>1.2</version>
</dependency>

三、總結

本章節重點闡述了spring中的自動裝配的幾種策略,又通過源碼分析了autowired注解的使用方式。

在spring3.0之后,有效的自動裝配策略分為bytype、byname、constructor三種方式。注解autowired默認使用bytype來自動裝配,如果存在類型的多個實例就嘗試使用byname匹配,如果通過byname也確定不了,可以通過primary和priority注解來確定。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://juejin.im/post/5c84b5285188257c5b477177

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产99久久久久久免费看农村 | 日韩av片在线播放 | 久久久一区二区精品 | 欧美一区二区三区四区五区动图 | 国产91精品一区二区麻豆亚洲 | 亚洲精品wwww | 97中文 | 蜜桃视频最新网址 | 在火车上摸两乳爽的大叫 | 在线a视频| 精品国产高清一区二区三区 | 久久伊 | 一级在线观看 | 亚洲小视频网站 | 2021av视频 | 国产一区二区观看 | 国产成人av免费看 | 色片免费在线观看 | 欧美一级毛片欧美一级成人毛片 | 法国极品成人h版 | 一级黄色免费观看视频 | chinese军人gay呻吟 | 91美女视频在线观看 | 激情午夜天 | 羞羞羞羞视频 | 福利在线播放 | 逼片| 欧美视屏一区二区 | 久久久免费观看完整版 | 草久在线 | 亚洲特黄a级毛片在线播放 激情视频免费看 | 神马视频我不卡 | 狼伊千合综网中文 | 91久久久久久亚洲精品禁果 | 久久99精品久久久久久国产越南 | 久久国产28 | 久久免费视频8 | 免费看日韩片 | 91丨九色丨国产在线观看 | 久久男人视频 | 在线免费观看日韩视频 |