Spring實現(xiàn)控制反轉(zhuǎn)和依賴注入的示例詳解
什么是控制反轉(zhuǎn)
控制反轉(zhuǎn)是軟件工程中的一個原則,它將對象或程序的某些部分的控制權(quán)轉(zhuǎn)移給容器或框架。我們最常在面向?qū)ο缶幊痰纳舷挛闹惺褂盟?/p>
與傳統(tǒng)編程相比,傳統(tǒng)編程中我們的自定義代碼調(diào)用庫,而IoC使框架控制程序的流程并調(diào)用我們的自定義代碼。為了實現(xiàn)這一點,框架使用具有附加行為的抽象。如果我們想要添加自己的行為,我們需要擴(kuò)展框架的類或插入自己的類。
這種架構(gòu)的優(yōu)點是:
- 將任務(wù)的執(zhí)行與其實現(xiàn)分離
- 更容易在不同實現(xiàn)之間切換
- 程序的更高的模塊化
- 更容易通過隔離組件或模擬其依賴項來測試程序,并允許組件通過契約進(jìn)行通信
我們可以通過各種機(jī)制實現(xiàn)IoC
,例如:策略設(shè)計模式、服務(wù)定位器模式、工廠模式和依賴注入(DI
)。
什么是依賴注入
依賴注入是一種我們可以用來實現(xiàn)IoC
的模式,其中被反轉(zhuǎn)的控制是設(shè)置對象的依賴項。
將對象與其他對象連接或?qū)ο?ldquo;注入”到其他對象中是由匯編程序而不是對象本身完成的。
下面是在傳統(tǒng)編程中創(chuàng)建對象依賴關(guān)系的方法:
public classStore { private Item item; public Store() { item =newItemImpl1(); } }
在上面的示例中,我們需要在*Store
類本身中實例化Item
*接口的實現(xiàn)。
通過使用DI
,我們可以重寫該示例,而不指定我們想要的*Item
*的實現(xiàn):
public classStore { private Item item; public Store(Item item) { this.item = item; } }
在接下來的幾節(jié)中,我們將看看如何通過元數(shù)據(jù)提供Item的實現(xiàn)。
IoC
和DI
都是簡單的概念,但它們對我們構(gòu)建系統(tǒng)的方式有深刻的影響,因此值得充分理解。
Spring IoC容器
IoC
容器是實現(xiàn)IoC
的框架的常見特征。
在Spring
框架中,接口ApplicationContext
表示IoC
容器。Spring
容器負(fù)責(zé)實例化、配置和組裝稱為bean
的對象,以及管理它們的生命周期。
Spring
框架提供了*ApplicationContext
接口的幾個實現(xiàn):
ClassPathXmlApplicationContext
和
FileSystemXmlApplicationContext
用于獨立應(yīng)用程序,以及
WebApplicationContext
*用于Web應(yīng)用程序。
為了組裝bean
,容器使用配置元數(shù)據(jù),可以是XML
配置或注釋形式。
以下是手動實例化容器的一種方法:
ApplicationContext context=newClassPathXmlApplicationContext("applicationContext.xml");
在上面的示例中,我們可以使用元數(shù)據(jù)設(shè)置*item
*屬性,然后容器將讀取此元數(shù)據(jù)并在運行時使用它來組裝bean
。
在Spring
中,可以通過構(gòu)造函數(shù)、setter
或字段來進(jìn)行依賴注入。
基于構(gòu)造函數(shù)的依賴注入
在基于構(gòu)造函數(shù)的依賴注入的情況下,容器將調(diào)用具有表示我們要設(shè)置的依賴項的參數(shù)的構(gòu)造函數(shù)。
Spring
通過類型解決每個參數(shù),然后按屬性名稱和索引進(jìn)行消歧。讓我們看看使用注釋配置bean
及其依賴項的配置:
@Configuration public class AppConfig { @Bean public Itemitem1() { return new ItemImpl1(); } @Bean public Storestore() { return new Store(item1()); } }
*@Configuration
*注釋表示該類是bean
定義的源。我們也可以將其添加到多個配置類中。
我們在方法上使用@Bean
注釋來定義bean
。如果我們沒有指定自定義名稱,則bean
名稱將默認(rèn)為方法名稱。
對于默認(rèn)的*singleton
范圍的bean
,Spring
首先檢查是否已存在緩存的bean
實例,僅在不存在時創(chuàng)建新實例。如果我們使用prototype
*范圍,則容器為每個方法調(diào)用返回一個新的bean
實例。
創(chuàng)建bean
的另一種方式是通過XML
配置:
<bean id="item1" class="org.baeldung.store.ItemImpl1" /> <bean id="store" class="org.baeldung.store.Store"> <constructor-arg type="ItemImpl1" index="0" name="item" ref="item1" /> </bean>
基于setter的依賴注入
對于基于setter
的DI
,容器將在調(diào)用沒有參數(shù)的構(gòu)造函數(shù)或沒有參數(shù)的靜態(tài)工廠方法來實例化bean
之后調(diào)用我們類的setter
方法。讓我們使用注釋創(chuàng)建此配置:
@Bean public Storestore() { Store store =newStore(); store.setItem(item1()); return store; }
我們也可以使用XML進(jìn)行相同的bean配置:
<bean id="store" class="org.baeldung.store.Store"> <property name="item" ref="item1" /> </bean>
我們可以將構(gòu)造函數(shù)和setter
類型的注入結(jié)合在同一個bean
中。Spring
文檔建議將基于構(gòu)造函數(shù)的注入用于必需的依賴項,將基于setter
的注入用于可選的依賴項。
基于字段的依賴注入
在基于字段的DI
的情況下,我們可以通過帶有@Autowired
注釋的注釋將依賴項注入其中:
public class Store { @Autowired private Item item; }
在構(gòu)造*Store
對象時,如果沒有構(gòu)造函數(shù)或setter
方法將Itembean注入其中,容器將使用反射將Item
注入Store
*中。
我們也可以使用XML
來實現(xiàn)這一點。
這種方法可能看起來更簡單、更清晰,但我們不建議使用它,因為它有一些缺點,例如:
- 此方法使用反射來注入依賴項,這比基于構(gòu)造函數(shù)或
setter
的注入更昂貴。 - 使用此方法很容易添加多個依賴項。如果我們使用構(gòu)造函數(shù)注入,有多個參數(shù)會讓我們認(rèn)為這個類做了不止一件事,這可能違反單一責(zé)任原則。
自動裝配依賴項
自動裝配允許Spring
容器通過檢查已定義的bean
來自動解決協(xié)作bean
之間的依賴關(guān)系。
使用XML
配置有四種自動裝配bean
的模式:
no
:默認(rèn)值 - 這意味著不使用自動裝配,我們必須顯式地命名依賴項。byName
:按屬性名稱進(jìn)行自動裝配,因此Spring
將查找與需要設(shè)置的屬性同名的bean
。byType
:類似于按名稱進(jìn)行自動裝配,僅基于屬性的類型。這意味著Spring
將查找具有相同類型的屬性來設(shè)置的bean
。如果有多個bean
具有該類型,則框架會拋出異常。constructor
:基于構(gòu)造函數(shù)參數(shù)進(jìn)行自動裝配,意味著Spring
將查找具有與構(gòu)造函數(shù)參數(shù)相同類型的bean
。
例如,讓我們通過類型創(chuàng)建具有依賴項*item
的store
*bean
。
public class AppConfig { @Bean public Item item() { return new ItemImpl1(); } @Bean(autowire = Autowire.BY_TYPE) public Store store() { return new Store(); } }
請注意,自Spring 5.1
起,*autowire
*屬性已棄用。
我們還可以使用@Autowired
注釋按類型注入bean
:
public class Store { @Autowired private Item item; }
如果存在相同類型的多個bean
,則可以使用@Qualifier
注釋按名稱引用bean
:
public class Store { @Autowired @Qualifier("item1") private Item item; }
現(xiàn)在,讓我們通過XML
配置按類型自動裝配bean
:
<bean id="store" class="org.baeldung.store.Store" autowire="byType"> </bean>
接下來,讓我們通過XML
按名稱將名為*item
的bean
注入到storebean的item
*屬性中:
<bean id="item" class="org.baeldung.store.ItemImpl1" /> <bean id="store" class="org.baeldung.store.Store" autowire="byName"> </bean>
我們還可以通過構(gòu)造函數(shù)參數(shù)或setter
顯式定義依賴關(guān)系來覆蓋自動裝配。
惰性初始化的bean
默認(rèn)情況下,容器在初始化期間創(chuàng)建和配置所有單例bean
。為了避免這種情況,我們可以在bean
配置上使用值為*true
的lazy-init
*屬性:
<bean id="item1" class="org.baeldung.store.ItemImpl1" lazy-init="true" />
因此,只有在第一次請求它時,才會初始化*item1
*bean
,而不是在啟動時。這樣做的優(yōu)點是初始化時間更快,但缺點是我們在bean
被請求之后才會發(fā)現(xiàn)任何配置錯誤,這可能是應(yīng)用程序已運行數(shù)小時甚至數(shù)天之后。
到此這篇關(guān)于Spring實現(xiàn)控制反轉(zhuǎn)和依賴注入的示例詳解的文章就介紹到這了,更多相關(guān)Spring控制反轉(zhuǎn) 依賴注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot在服務(wù)器上的幾種啟動方式(小結(jié))
這篇文章主要介紹了springboot在服務(wù)器上的幾種啟動方式(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09Java中將List拆分為多個小list集合的實現(xiàn)代碼
這篇文章主要介紹了Java中如何將List拆分為多個小list集合,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03java中File類的三種創(chuàng)建文件夾方法總結(jié)
這篇文章主要給大家介紹了關(guān)于java中File類的三種創(chuàng)建文件夾方法,File類代表文件或目錄路徑名的抽象表達(dá)形式,通過File類提供的方法,我們可以很方便地創(chuàng)建文件夾,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04