欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2019年03月13日 14:13:18   作者:清幽之地  
這篇文章主要介紹了徹底搞明白Spring中的自動裝配和Autowired注解的使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一、自動裝配

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

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

當(dāng)涉及到自動裝配Bean的依賴關(guān)系時,Spring有多種處理方式。因此,Spring提供了4種自動裝配策略。

public interface AutowireCapableBeanFactory{

 //無需自動裝配
 int AUTOWIRE_NO = 0;

 //按名稱自動裝配bean屬性
 int AUTOWIRE_BY_NAME = 1;

 //按類型自動裝配bean屬性
 int AUTOWIRE_BY_TYPE = 2;

 //按構(gòu)造器自動裝配
 int AUTOWIRE_CONSTRUCTOR = 3;

 //過時方法,Spring3.0之后不再支持
 @Deprecated
 int AUTOWIRE_AUTODETECT = 4;
}

Spring在AutowireCapableBeanFactory接口中定義了這幾種策略。其中,AUTOWIRE_AUTODETECT被標(biāo)記為過時方法,在Spring3.0之后已經(jīng)不再支持。

1、byName

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

首先,在User的Bean中有個屬性Role myRole,再創(chuàng)建一個Role的Bean,它的名字如果叫myRole,那么在User中就可以使用byName來自動裝配。

public class User{
 private Role myRole;
}
public class Role {
 private String id; 
 private String name;
}

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

<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的名稱可以對應(yīng),那么在user的Bean中就可以使用byName來自動裝配。那么,如果屬性名稱對應(yīng)不上呢?

2、byType

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

<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的構(gòu)造器入?yún)⒕哂邢嗤愋偷钠渌鸅ean自動裝配到Bean構(gòu)造器的對應(yīng)入?yún)⒅?。值的注意的是,具有相同類型的其他Bean這句話說明它在查找入?yún)⒌臅r候,還是通過Bean的類型來確定。
構(gòu)造器中入?yún)⒌念愋蜑镽ole

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之后已經(jīng)被標(biāo)記為@Deprecated。

5、默認(rèn)自動裝配

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

在根元素Beans上增加屬性default-autowire="byType"。

<beans default-autowire="byType">

Spring自動裝配的優(yōu)點不言而喻。但是事實上,在Spring XML配置文件里的自動裝配并不推薦使用,其中筆者認(rèn)為最大的缺點在于不確定性?;蛘叱悄銓φ麄€Spring應(yīng)用中的所有Bean的情況了如指掌,不然隨著Bean的增多和關(guān)系復(fù)雜度的上升,情況可能會很糟糕

二、Autowired

從Spring2.5開始,開始支持使用注解來自動裝配Bean的屬性。它允許更細粒度的自動裝配,我們可以選擇性的標(biāo)注某一個屬性來對其應(yīng)用自動裝配。

Spring支持幾種不同的應(yīng)用于自動裝配的注解。

  • Spring自帶的@Autowired注解。
  • JSR-330的@Inject注解。
  • JSR-250的@Resource注解。

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

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

@Autowired
UserService userService;

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

1、強制性

默認(rèn)情況下,它具有強制契約特性,其所標(biāo)注的屬性必須是可裝配的。如果沒有Bean可以裝配到Autowired所標(biāo)注的屬性或參數(shù)中,那么你會看到NoSuchBeanDefinitionException的異常信息。

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集合為空不要緊,關(guān)鍵isRequired條件不能成立,那么,如果我們不確定屬性是否可以裝配,可以這樣來使用Autowired。

@Autowired(required=false)
UserService userService;

2、裝配策略

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

默認(rèn)按照類型裝配

關(guān)鍵點findAutowireCandidates這個方法。

protected Map<String, Object> findAutowireCandidates(
 String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
 
 //獲取給定類型的所有bean名稱,里面實際循環(huán)所有的beanName,獲取它的實例
 //再通過isTypeMatch方法來確定
 String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  this, requiredType, true, descriptor.isEager());
  
 Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
 
 //根據(jù)返回的beanName,獲取其實例返回
 for (String candidateName : candidateNames) {
 if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
  result.put(candidateName, getBean(candidateName));
 }
 }
 return result;
}

按照名稱裝配

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

比如,按照UserService接口類型來裝配它的實現(xiàn)類。UserService接口有多個實現(xiàn)類,分為UserServiceImpl、UserServiceImpl2。那么我們在注入的時候,就可以把屬性名稱定義為Bean實現(xiàn)類的名稱。

@Autowired
UserService UserServiceImpl2;

這樣的話,Spring會按照byName來進行裝配。首先,如果查到類型的多個實例,Spring已經(jīng)做了判斷。

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方法就是關(guān)鍵。它來確定一個合適的Bean返回。其中一部分就是按照Bean的名稱來匹配。

protected String determineAutowireCandidate(Map<String, Object> candidateBeans, 
  DependencyDescriptor descriptor) {
 //循環(huán)拿到的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默認(rèn)使用byType來裝配屬性,如果匹配到類型的多個實例,再通過byName來確定Bean。

3、主和優(yōu)先級

上面我們已經(jīng)看到了,通過byType可能會找到多個實例的Bean。然后再通過byName來確定一個合適的Bean,如果通過名稱也確定不了呢?

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

protected String determineAutowireCandidate(Map<String, Object> candidateBeans, 
  DependencyDescriptor descriptor) {
 Class<?> requiredType = descriptor.getDependencyType();
 //通過@Primary注解來標(biāo)識Bean
 String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType);
 if (primaryCandidate != null) {
 return primaryCandidate;
 }
 //通過@Priority(value = 0)注解來標(biāo)識Bean value為優(yōu)先級大小
 String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType);
 if (priorityCandidate != null) {
 return priorityCandidate;
 }
 return null;
}

Primary

它的作用是看Bean上是否包含@Primary注解,如果包含就返回。當(dāng)然了,你不能把多個Bean都設(shè)置為@Primary,不然你會得到NoUniqueBeanDefinitionException這個異常。

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,可以配置優(yōu)先級大小。數(shù)字越小的,就被優(yōu)先匹配。同樣的,你也不能把多個Bean的優(yōu)先級配置成相同大小的數(shù)值,否則NoUniqueBeanDefinitionException異常照樣出來找你。

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) {
  //如果優(yōu)先級大小相同
  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;,如果想使用它還要引入一個坐標(biāo)。

<dependency>
 <groupId>javax.annotation</groupId>
 <artifactId>javax.annotation-api</artifactId>
 <version>1.2</version>
</dependency>

三、總結(jié)

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

在Spring3.0之后,有效的自動裝配策略分為byType、byName、constructor三種方式。注解Autowired默認(rèn)使用byType來自動裝配,如果存在類型的多個實例就嘗試使用byName匹配,如果通過byName也確定不了,可以通過Primary和Priority注解來確定。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 使用MappingJackson2XmlView實現(xiàn)JSON到XML的視圖轉(zhuǎn)換

    使用MappingJackson2XmlView實現(xiàn)JSON到XML的視圖轉(zhuǎn)換

    MappingJackson2XmlView來實現(xiàn)從JSON到XML格式的響應(yīng)轉(zhuǎn)換,本文將通過案例,將展示如何將JSON格式的數(shù)據(jù)轉(zhuǎn)換為XML格式,以滿足不同客戶端的數(shù)據(jù)交換需求,需要的朋友可以參考下
    2024-07-07
  • Java SSL與TLS客戶端證書配置方式

    Java SSL與TLS客戶端證書配置方式

    這篇文章主要介紹了Java SSL與TLS客戶端證書配置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 最簡單易懂的java數(shù)組排序方法整理

    最簡單易懂的java數(shù)組排序方法整理

    這篇文章主要給大家整理介紹了最簡單易懂的java數(shù)組排序方法,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • Aspectj框架實戰(zhàn)案例詳解

    Aspectj框架實戰(zhàn)案例詳解

    這篇文章主要介紹了Aspectj框架實戰(zhàn),結(jié)合具體案例形式詳細分析了Aspectj框架具體配置、使用、編譯等相關(guān)操作技巧,需要的朋友可以參考下
    2020-01-01
  • 在IDEA中maven配置MyBatis的流程詳解

    在IDEA中maven配置MyBatis的流程詳解

    剛學(xué)完javaweb,對自己的Dao層代碼很不滿意的話,可得來學(xué)學(xué)MyBatis.學(xué)習(xí)MyBatis既可以改進JDBC的使用,實現(xiàn)Dao層也會變得很簡便,下面我將介紹IDEA中maven配置MyBatis簡單流程,需要的朋友可以參考下
    2021-06-06
  • Hadoop源碼分析四遠程debug調(diào)試

    Hadoop源碼分析四遠程debug調(diào)試

    本篇是Hadoop源碼分析系列文章第四篇,主要介紹一下Hadoop的遠程debug調(diào)試步驟,后續(xù)本系列文章會持續(xù)更新,有需要的朋友可以借鑒參考下
    2021-09-09
  • Springboot mybatis plus druid多數(shù)據(jù)源解決方案 dynamic-datasource的使用詳解

    Springboot mybatis plus druid多數(shù)據(jù)源解決方案 dynamic-datasource的使用詳

    這篇文章主要介紹了Springboot mybatis plus druid多數(shù)據(jù)源解決方案 dynamic-datasource的使用,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • 詳解Java 反射和反射的應(yīng)用場景

    詳解Java 反射和反射的應(yīng)用場景

    這篇文章主要介紹了Java 反射和反射的應(yīng)用場景的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java反射的相關(guān)知識,感興趣的朋友可以了解下
    2020-08-08
  • Java?I/O流之打印流詳細使用方法教程

    Java?I/O流之打印流詳細使用方法教程

    java的io是實現(xiàn)輸入和輸出的基礎(chǔ),可以方便的實現(xiàn)數(shù)據(jù)的輸入和輸出操作,下面這篇文章主要給大家介紹了關(guān)于Java?IO流打印流詳細使用的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-01-01
  • Java 多線程之間共享數(shù)據(jù)

    Java 多線程之間共享數(shù)據(jù)

    這篇文章主要介紹了Java 多線程之間共享數(shù)據(jù),圍繞Java 多線程之間共享數(shù)據(jù)展開文章內(nèi)容線程范圍的共享變量、使用Map實現(xiàn)線程范圍內(nèi)數(shù)據(jù)的共享、ThreadLocal實現(xiàn)線程范圍內(nèi)數(shù)據(jù)的共享,需要的朋友可以參考一下
    2021-10-10

最新評論