引用文章地址:
https://my.oschina.net/HeliosFly/blog/203902(重點推薦!!!!!)
http://wiki.jikexueyuan.com/project/spring/annotation-based-configuration/spring-autowired-annotation.html
https://www.tianmaying.com/tutorial/spring-auto-wiring
http://www.cnblogs.com/liuzy2014/p/6692781.html
http://blog.csdn.net/baple/article/details/17891755
前言:
@Autowired註解代碼定義
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Autowired { boolean required() default true;}
從上述定義中,我們可以得出@Autowired註解只有一個屬性即required屬性,此屬性的預設值為true,即預設情況下它要求依賴對象必須存在,如果不存在會出現null 指標等錯誤;如果允許為null,可以設定它required屬性為false.其中@Autowired註解和標註的變數的類的set和get方法無關,自動裝配的實現並不是依賴set方法的方式實現的.在xml中利用
<property name="" value="" />
這種方式是依賴對應類的set方法的方式實現的 @Autowired註解使用之前首先確定判斷一下此處能夠使用@Autowired註解.
一、 @Autowired註解使用情境介紹
(1)建構函式(2)成員變數(3)Setter方法(4)普通方法
二、 @Autowired註解所涉及的原理部分
其實在啟動spring IoC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor後置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IoC容器自動尋找需要的bean,並裝配給該對象的屬性
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
注意事項:
在使用@Autowired時,首先在容器中查詢對應類型的bean, 如果查詢結果剛好為一個,就將該bean裝配給@Autowired指定的資料 如果查詢的結果不止一個,那麼@Autowired會根據名稱來尋找。 如果查詢的結果為空白,那麼會拋出異常。解決方案時,使用required=false
上述過程說明了@Autowired註解預設是按照類型裝配注入的,預設情況下它要求依賴對象必須存在如果允許為null,可以設定它required屬性為false,如果想按照名稱來轉配注入,則需要結合@Qualifier一起使用;
三、 處理使用@Autowired註解出現自動裝配的歧義性問題
使用@Autowired註解的過程中,如果出現NoUniqueBeanDefinitionException異常,大多是因為自動裝配或者其他方式裝配所導致的歧義性.即一個介面存在兩個以上的實作類別.即在自動裝配的時候,可能出現因重名問題導致的NoUniqueBeanDefinitionException異常.
@Autowired是按類型進行裝配的,那麼我一個介面UserInterface,有多個實作類別
AImpl(@service(name="userInterface1")),BImpl(@service(name="userInterface2")
等等這些實作類別都加入了Spring容器,當在一個類中使用如下語句:
@Autowiredprivate IUserInterface userInterface;
在下面列舉一下了一下,上述問題以及類似的裝配歧義性解決問題方法.
方法一
首先加上註解@Qualifier來區分不同的執行個體.通過在實現介面的類上通過value屬性去命名不同的名稱,對於@Repository、@Service 和 @Controller 和 @Component四個註解都有類似value屬性可以設定,例如:
@Service(value="userServiceImpl")public class UserServiceImpl implements IUserService{}@Autowired@Qualifier("userServiceImpl")private IUserService userServiceImpl;
方法二
因為一個借口存在兩個以上的實作類別,也可以通過標識首選哪個bean,來解決歧義性問題.例如:
@Component@Primarypublic class UserServiceImpl implements IUserService{ }
此時,如果引用到了IUserService介面的實作類別注入,則首先注入@Promary註解標註的類,但是此時有一個問題,在同一個介面的實作類別中,你只能使用一次@Primary,如果對於AImpl和BImpl都使用了@primary,則還是會發生裝配的歧義性.此時,建議使用(1)的方式來解決歧義性問題.
<4>方法三
最後一種方式,可以使用自訂的限定符註解,但是此種情況很少出現,再次就不做介紹,可自行百度.
四、 Spring通過哪些特性實現自動裝配的?
Spring從兩個角度來實現自動化裝配:
(1)組件掃描(component scanning):Spring會自動探索應用上下文中所建立的bean.(2)自動裝配(autowiring):Spring自動滿足bean之間的依賴.
組件掃描和自動裝配組合在一起就能發揮出強大的威力,它們能夠將你的顯示配置降低到最少.
五、@Autowired和@Resource之間的區別
在本文只列舉出@Autowired和@Resource之間常見的表面區別,至於區別的原因需要查看Spring官方文檔中的@Autowired註解實現方式和Java中@Resource註解實現方式.
(1)、@Autowired預設是按照類型裝配注入的,預設情況下它要求依賴對象必須存在如果允許為null,可以設定它required屬性為false,如果想按照名稱來轉配注入,則需要結合@Qualifier一起使用;
(2)、@Resource預設是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean才會按照類型來裝配注入;
(3)、@Resource註解是由J2EE提供,而@Autowired是由spring提供,故減少系統對spring的依賴建議使用@Resource的方式;
(4)、@Resource和@Autowired都可以書寫標註在欄位或者該欄位的setter方法之上
(5)、@Resource預設按照名稱裝配,當找不到與名稱匹配的bean才會按照類型裝配,可以通過name屬性指定,如果沒有指定name屬 性,當註解標註在欄位上,即預設取欄位的名稱作為bean名稱尋找依賴對象,當註解標註在屬性的setter方法上,即預設取屬性名稱作為bean名稱尋找 依賴對象.注意:如果沒有指定name屬性,並且按照預設的名稱仍然找不到依賴的對象時候,會回退到按照類型裝配,但一旦指定了name屬性,就只能按照名稱裝配了.
六、Spring是如何啟動自動掃描的
在這裡列舉出三種啟動自動掃描的方式.
方式一:此種情況下,針對比較特殊的情形,即項目中運用了SpringBoot,則可以利用@SpringBootApplication註解的方式啟動自動掃描功能.
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
方式二:通過XML配置方式,啟動自動掃描功能.XML配置方式
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.tianmaying" /></beans>
標籤將會開啟Spring Beans的自動掃描,並可設定base-package屬性,表示Spring將會掃描該目錄以及子目錄下所有被@Component標註修飾的類,對它們進行裝配。
方式三:通過Java配置方式,啟動自動掃描功能.
import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScan(basePackages = "com.cn.config")public class BlogSystemConfig { /** * 在這裡實現java方式的配置, */}
在這裡給出一個具體的執行個體:
import org.apache.commons.dbcp.BasicDataSource;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScan(basePackages = "com.cn.config")public class DataSourceConfig { @Bean(name="dataSource")//java配置方式,配置資料來源(dataSource) public BasicDataSource dataSource(){ BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName("org.postgresql.Driver"); dataSource.setUrl("jdbc:postgresql://127.0.0.1:5432/center_db?useUnicode=true&characterEncoding=UTF-8"); dataSource.setUsername("postgres"); dataSource.setPassword("123456"); dataSource.setInitialSize(5); dataSource.setMaxActive(10); return dataSource; }}
關於@Configuration和@ComponentScan兩個註解:
(1)@Configuration表示這個Java檔案是一個設定檔,這類Java代碼的作用在於配置,要和普通的Java代碼區分開發,因此一般我們需要將其放在一個專門的包中,在代碼例子中是com.cn.config。
(2)@ComponentScan表示開啟Spring Beans掃描,類似於XML配置,這裡也可以可以設定basePackages屬性。
如果@ComponentScan註解沒有顯示去給其他的屬性賦值的話,比如此處給basePackages賦值了,如果沒有的話,@ComponentScan註解會掃描與配置類相同的包.
注意:
關於@Repository、@Service 和 @Controller 和 @Component四個註解的使用情形
在持久層、業務層和控制層分別採用 @Repository、@Service 和 @Controller 對分層中的類進行注釋,而用 @Component 對那些比較中立的類進行注釋.這裡就是說把這個類交給Spring管理,重新起個名字叫userManager,由於不好說這個類屬於哪個層面,就用@Component.
七、Spring存在幾種裝配方式?
目前,在Spring中,一共提供三種裝配方式:
(1)基於標註的自動裝配 (2)基於XML配置的顯式裝配 (3)基於Java配置的顯式裝配
在實際項目中,一般是上述三種裝備方式都可能存在,不過基於標註的自動裝配方式是在項目中最常用的.通過給Java類增加相應的標註,就能夠啟用Spring隱式的Bean發現機制,並自動完成裝配過程.我們在開發中應該儘可能使用自動裝配,足以應付開發中的絕大多數情況.在某些情況下,基於XML配置和基於Java配置的顯式裝配會有用武之地,比如執行個體化一個第三方庫中的Bean.這種情況下,Java配置和XML配置我們優先使用Java配置,因為這是一種型別安全的方式,能夠在編譯時間就儘早發現錯誤.
關於上述所說的型別安全可以這樣理解:
如果使用字串的形式,在xml中類名或其他寫入程式碼方式提供的資訊,在開發時是發現不了的,會在運行時拋出異常。而使用Java配置形式,類名或其他寫入程式碼配置資訊寫錯的話,編譯時間就會提示錯誤,比如Eclipse中就會提示找不到類的錯誤資訊,這就避免了這種情況下的運行時異常,因此是更加安全的.