淺談spring DI 依賴註入方式和區別
spring DI
Spring框架對Java開發的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反轉)和AOP,平時使用最多的就是其中的IOC,我們通過將組件交由Spring的IOC容器管理,將對象的依賴關系由Spring控制,避免硬編碼所造成的過度程序耦合。
3種DI註解的區別
1 @Autowired
使用特點
- Autowired註解是spring框架提供的
- Autowired註解優先byType獲取java bean,其次byName
- Autowired註解配合Qualifier註解區分java bean的名稱,主要用於同一個類型的javabean有多個實
- Autowired註解註入的對象,一般要求非null,如果允許為null,需要required=false屬性聲明
- @Autowired可以作用在變量、setter方法、構造函數上
使用過程
a、 將@autowored寫在被註入的成員變量上,就不用再xml文件中配置瞭,在程序中去掉相應的setter和getter方法,
b、 還可以寫在構造方法上、setter方法上
c、@Qualifier
@Qualifier(“XXX”) 中的 XX是 Bean 的名稱,所以 @Autowired 和 @Qualifier 結合使用時,自動註入的策略就從 byType 轉變成 byName 瞭。
不過需要註意的是@Autowired 可以對成員變量、方法以及構造函數進行註釋,而 @Qualifier 的標註對象是成員變量、方法入參、構造函數入參。
2 @Inject
使用特點
- @Inject是JSR330 (Dependency Injection for Java)中的規范,需要導入javax.inject.Inject; 實現註入
- @Inject是根據類型進行自動裝配的,如果需要按名稱進行裝配,則需要配合@Named
- @Inject可以作用在變量、setter方法、構造函數上
- 與@Autowired使用類似,想比之下,采用spring提供的@Autowired更為普遍
使用過程
a、 將@Inject可以作用在變量、setter方法、構造函數上,和@Autowired一樣
b、@Named
@Named(“XXX”) 中的 XX是 Bean 的名稱,所以 @Inject和 @Named結合使用時,自動註入的策略就從 byType 轉變成 byName 瞭。
3 @Resource
使用特點
- esource註解是jdk提供的,屬於j2ee規范
- Resource註解優先byname獲取java bean,其次byType
- Resource註解的屬性名稱作為java bean的名稱進行查找,如果有name參數,則使用name參數查找java bean
- Resource註解如果聲明瞭name屬性,則必須按照name查找對象,不會再使用類型查找
- @Resource可以作用在變量、setter方法上
使用過程
a、@Resource實例
3種註入方式的區別
註意項
- 註入方式:field註入、setter註入與構造器註入
- spring推薦使用setter方法和構造器註入Autowired的bean對象,因此IDEA等工具中私有屬性使用Autowired註入會提示警告。setter方法和構造器註入的方式,可以讓對象不依賴於spring而獨立使用,更加靈活;私有屬性則隻能通過spring上下文自動註入,一旦註入失敗,沒有重新註入的方式。
- @Resource不能用於構造器註入
1 field註入
@Controller public class FooController { @Autowired //@Inject private FooService fooService; //簡單的使用例子,下同 public List<Foo> listFoo() { return fooService.list(); } }
這種註入方式應該是最常見的註入方式。原因很簡單:
- 註入方式簡單:加入要註入的字段,附上@Autowired,即可完成。
- 使得整體代碼簡潔明瞭,看起來美觀大方。
2 構造器註入
@Controller public class FooController { private final FooService fooService; @Autowired public FooController(FooService fooService) { this.fooService = fooService; } //使用方式上同,略 }
Spring4.x版本中推薦的註入方式,相較於field註入方式,就顯得有點難看,特別是當註入的依賴很多(5個以上)的時候,就會明顯的發現代碼臃腫。
構造器註入的好處後面單獨討論。
3 setter註入
@Controller public class FooController { private FooService fooService; //使用方式上同,略 @Autowired public void setFooService(FooService fooService) { this.fooService = fooService; } }
在Spring3.x剛推出的時候,推薦使用註入的就是這種,現在很少使用這種註解方式,寫起來麻煩,當初推薦Spring自然也有他的道理: 構造器註入參數太多瞭,顯得很笨重,另外setter的方式能用讓類在之後重新配置或者重新註入。
構造器註入的好處
Spring在文檔裡怎麼說:
The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.
簡單的翻譯一下:構造器註入的方式,能夠保證註入的組件不可變,並且確保需要的依賴不為空。此外,構造器註入的依賴總是能夠在返回客戶端(組件)代碼的時候保證完全初始化的狀態。
1 依賴不可變
屬性使用final關鍵字修飾
2 依賴不為空
(省去瞭我們對null的檢查)
當要實例化類的時候,由於類已經實現瞭有參數的構造函數,所以不會調用默認構造函數,那麼就需要Spring容器傳入所需要的參數,所以就兩種情況:1、有該類型的參數->傳入,OK 。2:無該類型的參數->報錯。所以保證不會為空,Spring不會傳一個null進去
如果使用field註入,缺點顯而易見,因為你不調用將一直無法發現NPE的存在。
3 完全初始化狀態
這個可以跟上面的依賴不為空結合起來,向構造器傳參之前,要確保註入的內容不為空,那麼肯定要調用依賴組件的構造方法完成實例化。而在Java類加載實例化的過程中,構造方法是最後一步(之前如果有父類先初始化父類,然後自己的成員變量,最後才是構造方法)。所以返回來的都是初始化之後的狀態。
4 避免循環依賴
使用field註入可能會導致循環依賴,即A裡面註入B,B裡面又註入A:
public class A { @Autowired private B b; } public class B { @Autowired private A a; }
使用構造器註入,在spring項目啟動的時候,就會拋出:BeanCurrentlyInCreationException:Requested bean is currently in creation: Is there an unresolvable circular reference?從而提醒你避免循環依賴;
如果是field註入的話,啟動的時候不會報錯,在使用那個bean的時候才會報錯。
5 總結
- 保證依賴不可變(final關鍵字)
- 保證依賴不為空(省去瞭我們對其檢查)
- 避免瞭循環依賴
- 當有一個依賴有多個實現的使用,推薦使用field註入或者setter註入的方式來指定註入的類型
Q1:跟3.x裡說的一樣,我要是有大量的依賴要註入,構造方法不會顯得很臃腫嗎?
對於這個問題,說明你的類當中有太多的責任,那麼你要好好想一想是不是自己違反瞭類的單一性職責原則,從而導致有這麼多的依賴要註入。
Q2:是不是其他的註入方式都不適合用瞭呢?
存在即是合理!setter的方式既然一開始被Spring推薦肯定是有它的道理,像之前提到的setter的方式能用讓類在之後重新配置或者重新註入,就是其優點之一。除此之外,如果一個依賴有多種實現方式,我們可以使用@Qualifier,在構造方法裡選擇對應的名字註入,也可以使用field或者setter的方式來手動配置要註入的實現。
到此這篇關於淺談spring DI 依賴註入方式和區別的文章就介紹到這瞭,更多相關spring DI 依賴註入內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 深入分析@Resource和@Autowired註解區別
- Java面試題沖刺第十八天–Spring框架3
- Spring Bean自動裝配入門到精通
- Spring中@Autowired與@Resource的區別詳析
- Spring為什麼不推薦使用@Autowired註解詳析