Java Spring 控制反轉(zhuǎn)(IOC)容器詳解
IoC 容器是 Spring 的核心,也可以稱為 Spring 容器。Spring 通過 IoC 容器來管理對象的實例化和初始化,以及對象從創(chuàng)建到銷毀的整個生命周期。
Spring 中使用的對象都由 IoC 容器管理,不需要我們手動使用 new 運算符創(chuàng)建對象。由 IoC 容器管理的對象稱為 Spring Bean,Spring Bean 就是 Java 對象,和使用 new 運算符創(chuàng)建的對象沒有區(qū)別。
Spring 通過讀取 XML 或 Java 注解中的信息來獲取哪些對象需要實例化。
Spring 提供 2 種不同類型的 IoC 容器,即 BeanFactory 和 ApplicationContext 容器。
什么是容器?
容器是一種為某種特定組件的運行提供必要支持的一個軟件環(huán)境。例如,Tomcat就是一個Servlet容器,它可以為Servlet的運行提供運行環(huán)境。類似Docker這樣的軟件也是一個容器,它提供了必要的Linux環(huán)境以便運行一個特定的Linux進程。
通常來說,使用容器運行組件,除了提供一個組件運行環(huán)境之外,容器還提供了許多底層服務(wù)。例如,Servlet容器底層實現(xiàn)了TCP連接,解析HTTP協(xié)議等非常復(fù)雜的服務(wù),如果沒有容器來提供這些服務(wù),我們就無法編寫像Servlet這樣代碼簡單,功能強大的組件。早期的JavaEE服務(wù)器提供的EJB容器最重要的功能就是通過聲明式事務(wù)服務(wù),使得EJB組件的開發(fā)人員不必自己編寫冗長的事務(wù)處理代碼,所以極大地簡化了事務(wù)處理。
無侵入容器
在設(shè)計上,Spring的IoC容器是一個高度可擴展的無侵入容器。所謂無侵入,是指應(yīng)用程序的組件無需實現(xiàn)Spring的特定接口,或者說,組件根本不知道自己在Spring的容器中運行。這種無侵入的設(shè)計有以下好處:
1.應(yīng)用程序組件既可以在Spring的IoC容器中運行,也可以自己編寫代碼自行組裝配置;
2.測試的時候并不依賴Spring容器,可單獨進行測試,大大提高了開發(fā)效率。
IOC控制反轉(zhuǎn)
Spring提供的容器又稱為IoC容器,什么是IoC?
Ioc—Inversion of Control,即“控制反轉(zhuǎn)”,不是什么技術(shù),是一個概念,是一種思想。指將傳統(tǒng)上由程序代 碼直接操控的對象調(diào)用權(quán)交給容器,通過容器來實現(xiàn)對象的裝配和管理??刂品崔D(zhuǎn)就是對對象控制權(quán)的轉(zhuǎn)移,從程序代碼本身反轉(zhuǎn)到了外部容器。通過容器實現(xiàn)對象的裝配和管理。通俗點講,將對象的創(chuàng)建權(quán)交給spring,我們需要new對象,則由spring幫我們創(chuàng)建,然后供我們使用。
那么必然的我們需要創(chuàng)建一個容器,同時需要一種描述來讓容器知道需要創(chuàng)建的對象與對象的關(guān)系。這個描述最具體表現(xiàn)就是我們可配置的文件。IoC的實質(zhì)是如何管理對象,傳統(tǒng)意義上我們使用new方式來創(chuàng)建對象,但在企業(yè)應(yīng)用開發(fā)的過程中,大量的對象創(chuàng)建都在程序中維護很容易造成資源浪費,并且不利于程序的擴展。
其實現(xiàn)方式多種多樣。當(dāng)前比較流行的實現(xiàn)方式是依賴 注入。應(yīng)用廣泛。
依賴:classA 類中含有 classB 的實例,在 classA 中調(diào)用 classB 的方法完成功能,即 classA 對 classB 有依賴。
IOC理論推導(dǎo)
傳統(tǒng)應(yīng)用程序開發(fā)的弊端
在理解IoC之前,我們先看看通常的Java組件是如何協(xié)作的。
我們先用我們原來的方式寫一段代碼 .
1、先寫一個UserDao接口
2、再去寫Dao的實現(xiàn)類
public class UserDaoOneImpl implements UserDao { @Override public void getUser() { System.out.println("One獲取用戶數(shù)據(jù)"); } }
3、然后去寫UserService的接口
4、最后寫Service的實現(xiàn)類
5、測試一下
6、再回到UserDao接口
把Userdao的實現(xiàn)類增加一個 .
public class UserDaoMyTwoImpl implements UserDao { @Override public void getUser() { System.out.println("Two獲取用戶數(shù)據(jù)"); } }
7、我們就需要去service實現(xiàn)類里面修改對應(yīng)的實現(xiàn)
public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoTwo(); @Override public void getUser() { userDao.getUser(); } }
在假設(shè), 我們再增加一個Userdao的實現(xiàn)類 .
public class UserDaoThreeImpl implements UserDao { @Override public void getUser() { System.out.println("Three獲取用戶數(shù)據(jù)"); } }
那么我們要使用Three , 又需要去service實現(xiàn)類里面修改對應(yīng)的實現(xiàn) . 假設(shè)我們的這種需求非常大 , 這種方式就根本不適用了, 甚至反人類對吧 , 每次變動 , 都需要修改大量代碼 . 這種設(shè)計的耦合性太高了, 牽一發(fā)而動全身 .
“注入”機制
注入應(yīng)用程序某個對象,應(yīng)用程序依賴的對象
依賴注入可以通過set()方法實現(xiàn)。但依賴注入也可以通過構(gòu)造方法實現(xiàn)。Spring的IoC容器同時支持屬性注入和構(gòu)造方法注入,并允許混合使用。
我們可以在需要用到他的地方 , 不去實現(xiàn)它 , 而是留出一個接口 , 利用set , 我們?nèi)ゴa里修改下 .
@Test public void test(){ UserServiceImpl service = new UserServiceImpl(); service.setUserDao( new UserDaoTwoImpl() ); service.getUser(); //那我們現(xiàn)在又想添加Three去實現(xiàn)呢 service.setUserDao( new UserDaoThreeImpl() ); service.getUser(); }
以前所有東西都是由程序去進行控制創(chuàng)建 , 而現(xiàn)在是由我們自行控制創(chuàng)建對象 , 把主動權(quán)交給了調(diào)用者 . 程序不用去管怎么創(chuàng)建,怎么實現(xiàn)了 . 它只負責(zé)提供一個接口 .
這種思想 , 從本質(zhì)上解決了問題 , 我們程序員不再去管理對象的創(chuàng)建了 , 更多的去關(guān)注業(yè)務(wù)的實現(xiàn) . 耦合性大大降低 . 這也就是IOC的原型 !
小結(jié)
傳統(tǒng)程序設(shè)計如圖,都是主動去創(chuàng)建相關(guān)對象然后再組合起來:
沒有什么是加一層解決不了的
當(dāng)有了IoC/DI的容器后,在客戶端類中不再主動去創(chuàng)建這些對象了
IOC本質(zhì)
IoC是Spring框架的核心內(nèi)容,使用多種方式完美的實現(xiàn)了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置實現(xiàn)IoC。
Spring容器在初始化時先讀取配置文件,根據(jù)配置文件或元數(shù)據(jù)創(chuàng)建與組織對象存入容器中,程序使用時再從Ioc容器中取出需要的對象。
控制反轉(zhuǎn)是一種通過描述(XML或注解)并通過第三方去生產(chǎn)或獲取特定對象的方式。在Spring中實現(xiàn)控制反轉(zhuǎn)的是IoC容器,其實現(xiàn)方法是依賴注入(Dependency Injection,DI)。
DI(依賴注入)
IoC的一個重點是在系統(tǒng)運行中,動態(tài)的向某個對象提供它所需要的其他對象。這一點是通過DI(Dependency Injection,依賴注入)來實現(xiàn)的。 比如對象A需要操作數(shù)據(jù)庫,以前我們總是要在A中自己編寫代碼來獲得一個Connection對象,有了 spring我們就只需要告訴spring,A中需要一個Connection,至于這個Connection怎么構(gòu)造,何時構(gòu)造,A不需要知道。在系統(tǒng)運行時,spring會在適當(dāng)?shù)臅r候制造一個Connection,然后像打針一樣,注射到A當(dāng)中,這樣就完成了對各個對象之間關(guān)系的控制。A需要依賴 Connection才能正常運行,而這個Connection是由spring注入到A中的,依賴注入的名字就這么來的。那么DI是如何實現(xiàn)的呢? Java 1.3之后一個重要特征是反射(reflection),它允許程序在運行的時候動態(tài)的生成對象、執(zhí)行對象的方法、改變對象的屬性,spring就是通過反射來實現(xiàn)注入的。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
MyBatis動態(tài)SQL標(biāo)簽用法實例詳解
本文通過實例代碼給大家介紹了MyBatis動態(tài)SQL標(biāo)簽用法,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-07-07SpringBoot?mybatis-plus使用json字段實戰(zhàn)指南
在現(xiàn)代應(yīng)用開發(fā)中經(jīng)常會使用JSON格式存儲和傳輸數(shù)據(jù),為了便捷地處理數(shù)據(jù)庫中的JSON字段,MyBatis-Plus提供了強大的JSON處理器,這篇文章主要給大家介紹了關(guān)于SpringBoot?mybatis-plus使用json字段的相關(guān)資料,需要的朋友可以參考下2024-01-01jar的MANIFEST.MF配置Class-Path, java -classpath設(shè)置無效的解
這篇文章主要介紹了jar的MANIFEST.MF配置Class-Path, java -classpath設(shè)置無效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07淺談一下SpringCloud中Hystrix服務(wù)熔斷和降級原理
這篇文章主要介紹了淺談一下SpringCloud中Hystrix服務(wù)熔斷和降級原理,Hystrix 是 Netflix 的一款開源的容錯框架,通過服務(wù)隔離來避免由于依賴延遲、異常,引起資源耗盡導(dǎo)致系統(tǒng)不可用的解決方案,需要的朋友可以參考下2023-05-05為什么wait和notify必須放在synchronized中使用
這篇文章主要介紹了為什么wait和notify必須放在synchronized中使用,文章圍繞主題的相關(guān)問題展開詳細介紹,具有一定的參考價值,需要的小伙伴可以參考以參考一下2022-05-05mybatis if test 不為空字符串且不為null的問題
這篇文章主要介紹了mybatis if test 不為空字符串且不為null的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03詳解Spring Boot實戰(zhàn)之Rest接口開發(fā)及數(shù)據(jù)庫基本操作
本篇文章主要介紹了Spring Boot實戰(zhàn)之Rest接口開發(fā)及數(shù)據(jù)庫基本操作,具有一定的參考價值,有興趣的可以了解一下2017-07-07