Spring IoC和DI深度解析
Spring 是包含了眾多?具?法的 IoC 容器.
IoC
什么是IoC?
像在類上?添加 @RestController 和@Controller 注解, 就是把這個(gè)對(duì)象交給Spring管理, Spring 框架啟動(dòng)時(shí)就會(huì)加載該類. 把對(duì)象交給Spring管理, 就是IoC思想.
IoC:Inversion of Control (控制反轉(zhuǎn)), 也就是說 Spring 是?個(gè)"控制反轉(zhuǎn)"的容器.
什么是控制反轉(zhuǎn)呢? 也就是控制權(quán)反轉(zhuǎn). 什么的控制權(quán)發(fā)?了反轉(zhuǎn)? 獲得依賴對(duì)象的過程被反轉(zhuǎn)了也就是說, 當(dāng)需要某個(gè)對(duì)象時(shí), 傳統(tǒng)開發(fā)模式中需要??通過 new 創(chuàng)建對(duì)象, 現(xiàn)在不需要再進(jìn)?創(chuàng)建, 把創(chuàng)建對(duì)象的任務(wù)交給容器, 程序中只需要依賴注? (Dependency Injection,DI)就可以了.
這個(gè)容器稱為:IoC容器. Spring是?個(gè)IoC容器, 所以有時(shí)Spring 也稱為Spring 容器.
引入
傳統(tǒng)實(shí)現(xiàn)思路
我們的實(shí)現(xiàn)思路是這樣的:
先設(shè)計(jì)輪?(Tire),然后根據(jù)輪?的??設(shè)計(jì)底盤(Bottom),接著根據(jù)底盤設(shè)計(jì)??(Framework),最后根據(jù)??設(shè)計(jì)好整個(gè)汽?(Car)。這?就出現(xiàn)了?個(gè)"依賴"關(guān)系:汽?依賴??,??依賴底盤,底盤依賴輪?.

代碼實(shí)現(xiàn)
public class Main {
public static void main(String[] args) {
Car car = new Car(21);
car.run();
Car car2 = new Car(17);
car2.run();
}
}
//汽車
class Car {
private Framework framework;
public Car(int size) {
framework = new Framework(size);
System.out.println("framework init...");
}
public void run() {
System.out.println("car run...");
}
}
//車身
class Framework {
private Bottom bottom;
public Framework(int size) {
bottom = new Bottom(size);
System.out.println("bottom init....");
}
}
//底盤
class Bottom {
private Tire tire;
public Bottom(int size) {
tire = new Tire(size);
System.out.println("tire init...");
}
}
//輪胎
class Tire {
private int size;
public Tire(int size) {
System.out.println("tire size:"+size);
}
}上面這樣的設(shè)計(jì)看起來沒問題,但是可維護(hù)性卻很低,因?yàn)樾枨罂赡軙?huì)越來越多,比如增加輪胎顏色,修改后的代碼如下:

我們可以看到,修改后的代碼會(huì)報(bào)錯(cuò),并且需要我們繼續(xù)修改

完整代碼如下:
public class Main {
public static void main(String[] args) {
Car car = new Car(21,"aaa");
car.run();
Car car2 = new Car(17,"bbb");
car2.run();
}
}
//汽車
class Car {
private Framework framework;
public Car(int size,String color) {
framework = new Framework(size,color);
System.out.println("framework init...");
}
public void run() {
System.out.println("car run...");
}
}
//車身
class Framework {
private Bottom bottom;
public Framework(int size,String color) {
bottom = new Bottom(size,color);
System.out.println("bottom init....");
}
}
//底盤
class Bottom {
private Tire tire;
public Bottom(int size,String color) {
tire = new Tire(size,color);
System.out.println("tire init...");
}
}
//輪胎
class Tire {
private int size;
private String color;
public Tire(int size,String color) {
System.out.println("tire size:"+size);
}
}從以上代碼可以看出,以上程序的問題是:當(dāng)最底層代碼改動(dòng)之后,整個(gè)調(diào)?鏈上的所有代碼都需要修改.
程序的耦合度?常?(修改?處代碼, 影響其他處的代碼修改)。
解決方案
我們嘗試改變實(shí)現(xiàn)方式:輪?依賴底盤, 底盤依賴??,??依賴汽?。

基于以上思路,我們把調(diào)?汽?的程序?例改造?下,把創(chuàng)建?類的?式,改為注?傳遞的?式。
完整代碼如下:
class Main {
public static void main(String[] args) {
Tire tire = new Tire(17, "red");
Bottom bottom = new Bottom(tire);
Framework framework = new Framework(bottom);
Car car = new Car(framework);
car.run();
}
}
//汽車
class Car {
private Framework framework;
public Car(Framework framework) {
this.framework = framework;
System.out.println("framework init...");
}
public void run() {
System.out.println("car run...");
}
}
//車身
class Framework {
private Bottom bottom;
public Framework(Bottom bottom) {
this.bottom = bottom;
System.out.println("bottom init....");
}
}
//底盤
class Bottom {
private Tire tire;
public Bottom(Tire tire) {
this.tire=tire;
System.out.println("tire init...");
}
}
//輪胎
class Tire {
private int size;
private String color;
public Tire(int size, String color) {
System.out.println("tire size:"+size+",color:"+color);
}
}代碼經(jīng)過以上調(diào)整,?論底層類如何變化,整個(gè)調(diào)?鏈?zhǔn)遣?做任何改變的,這樣就完成了代碼之間的解耦,從?實(shí)現(xiàn)了更加靈活、通?的程序設(shè)計(jì)了。
IoC的優(yōu)勢(shì)
在傳統(tǒng)的代碼中對(duì)象創(chuàng)建順序是:Car -> Framework -> Bottom -> Tire
改進(jìn)之后解耦的代碼的對(duì)象創(chuàng)建順序是:Tire -> Bottom -> Framework -> Car

我們發(fā)現(xiàn)了?個(gè)規(guī)律,通?程序的實(shí)現(xiàn)代碼,類的創(chuàng)建順序是反的,傳統(tǒng)代碼是 Car 控制并創(chuàng)建了Framework,F(xiàn)ramework 創(chuàng)建并創(chuàng)建了 Bottom,依次往下,?改進(jìn)之后的控制權(quán)發(fā)?的反轉(zhuǎn),不再是使??對(duì)象創(chuàng)建并控制依賴對(duì)象了,?是把依賴對(duì)象注?將當(dāng)前對(duì)象中,依賴對(duì)象的控制權(quán)不再由當(dāng)前類控制了.
這樣的話, 即使依賴類發(fā)?任何改變,當(dāng)前類都是不受影響的,這就是典型的控制反轉(zhuǎn),也就是 IoC 的實(shí)現(xiàn)思想。
到這?, 我們?概就知道了什么是控制反轉(zhuǎn)了, 那什么是控制反轉(zhuǎn)容器呢, 也就是IoC容器。

這部分代碼, 就是IoC容器做的?作.
從上?也可以看出來, IoC容器具備以下優(yōu)點(diǎn):
資源不由使?資源的雙?管理,?由不使?資源的第三?管理,這可以帶來很多好處。
第?,資源集中管理,實(shí)現(xiàn)資源的可配置和易管理。
第?,降低了使?資源雙?的依賴程度,也就是我們說的耦合度。
1. 資源集中管理: IoC容器會(huì)幫我們管理?些資源(對(duì)象等), 我們需要使?時(shí), 只需要從IoC容器中去取就可以了
2. 我們?cè)趧?chuàng)建實(shí)例的時(shí)候不需要了解其中的細(xì)節(jié), 降低了使?資源雙?的依賴程度, 也就是耦合度.
Spring 就是?種IoC容器, 幫助我們來做了這些資源管理.
DI
DI: Dependency Injection(依賴注?)
容器在運(yùn)?期間, 動(dòng)態(tài)的為應(yīng)?程序提供運(yùn)?時(shí)所依賴的資源,稱之為依賴注?。
程序運(yùn)?時(shí)需要某個(gè)資源,此時(shí)容器就為其提供這個(gè)資源.
從這點(diǎn)來看, 依賴注?(DI)和控制反轉(zhuǎn)(IoC)是從不同的?度的描述的同?件事情,就是指通過引? IoC 容器,利?依賴關(guān)系注?的?式,實(shí)現(xiàn)對(duì)象之間的解耦。
前面代碼中, 是通過構(gòu)造函數(shù)的?式, 把依賴對(duì)象注?到需要使?的對(duì)象中的。

IoC 是?種思想,也是"?標(biāo)", ?思想只是?種指導(dǎo)原則,最終還是要有可?的落地?案,? DI 就屬于具體的實(shí)現(xiàn)。所以也可以說, DI 是IoC的?種實(shí)現(xiàn).
到此這篇關(guān)于Spring IoC和DI深度解析的文章就介紹到這了,更多相關(guān)Spring IoC和DI內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Struts2學(xué)習(xí)教程之?dāng)r截器機(jī)制與自定義攔截器
這篇文章主要給大家介紹了關(guān)于Struts2學(xué)習(xí)基礎(chǔ)教程之?dāng)r截器機(jī)制與自定義攔截器的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05
Java實(shí)現(xiàn)刪除文件中的指定內(nèi)容
在日常開發(fā)中,經(jīng)常需要對(duì)文本文件進(jìn)行批量處理,其中,刪除文件中指定內(nèi)容是最常見的需求之一,下面我們就來看看如何使用java實(shí)現(xiàn)刪除文件中的指定內(nèi)容吧2025-06-06
Java FTPClient連接池的實(shí)現(xiàn)
這篇文章主要介紹了Java FTPClient連接池的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06
詳解Java數(shù)據(jù)結(jié)構(gòu)和算法(有序數(shù)組和二分查找)
本篇文章主要介紹了詳解Java數(shù)據(jù)結(jié)構(gòu)和算法(有序數(shù)組和二分查找),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09

