javascript
Spring-IoC容器
- 導讀
- Ioc概述
- 通過分配工作的實例來理解Ioc的概念
- IoC類型
- 構造函數注入
- 屬性注入
- 通過容器完成依賴關系的注入
- 涉及的Java知識-Java反射
導讀
為了更好地理解Spring的IoC容器,在這里我們通過具體的日常工作中分配工作的示例來模擬IOC的概念。
同時,Spring實現依賴注入的Java底層技術是 Java反射,因此我們也會對Java反射進行介紹。
Ioc概述
Ioc (Inverse of Control 控制反轉 )是 Spring容器的內核,AOP、聲明式事務等功能都是以此為基礎。
通過分配工作的實例來理解Ioc的概念
舉個例子,日常工作(設計、開發、測試、集成等等)
小明直接處理開發工作:
================DoDistributedWork ========================== package com.xgj.master.ioc;import com.xgj.master.ioc.distributor.ProjectManager; import com.xgj.master.ioc.intf.Dealer; import com.xgj.master.ioc.specific.DealerImpl; import com.xgj.master.ioc.specific.XiaoMing;public class DoDistributedWork {/*** * @Title: doDevelopWork* @Description: 小明和具體的工作強耦合* @return: void*/public void doDevelopWork(){//小明直接侵入開發工作XiaoMing xiaoMing = new XiaoMing();xiaoMing.doWork();}...... }=========================XiaoMing ==========================package com.xgj.master.ioc.specific; public class XiaoMing {public void doWork() {System.out.println(XiaoMing.class.getSimpleName() + " says that he will do the develop work");} }讓我們來看下此時的類關系圖
可以發現: 開發工作和小明強耦合.
明智的管理者,會從工作分配的角度出發,而不會讓工作和具體的處理人員強耦合的 ,那如何讓小明和開發工作解耦呢?
同樣的開發工作,小強小剛等都可以勝任,而不是綁定到小明一個人身上? 那該如何處理呢?
通過上述分析,我們知道需要為處理人員定義一個接口,任何實現了該接口的實現類都可以處理開發工作。
package com.xgj.master.ioc.intf;public interface Dealer {/*** * @Title: doDevelopWork* @Description: 接口方法* @return: void*/public void doDevelopWork(); }接下來,只要繼承該接口,就可以勝任開發工作
package com.xgj.master.ioc.specific;import com.xgj.master.ioc.intf.Dealer;public class DealerImpl implements Dealer{@Overridepublic void doDevelopWork() {System.out.println(DealerImpl.class.getSimpleName() +" says that he will do the work"); } }分配工作:
/*** * @Title: doDevelopWork2* @Description: 引入接口,只奧是使具體的執行者和開發工作解耦* @return: void* */public void doDevelopWork2(){// 引入接口 DealerDealer dealer = new DealerImpl();// 通過接口處理對應的工作dealer.doDevelopWork();}此時的UML:
此時我們發現:
DoDistrubuteWork 同時依賴 Dealer 和 DealerImpl,需要在DoDistrubuteWork 創建DealerImpl,并沒有實現 工作只依賴Dealer的效果。
但是Dealer必須通過具體的實現類才能完成工作,如何讓DealerImpl 和 DoDistrubuteWork 無關 同時又能完成Dealer 的具體動作呢?
我們引入 PM,UML關系圖如下
/*** * @Title: pmDistributeWork* @Description: 引入PM,使 工作和具體的執行者解耦* @return: void*/public void pmDistributeWork(){// 引入PMProjectManager projectManager = new ProjectManager();// PM分配工作projectManager.distributeWork();}通過引入PM,使得 工作和 具體的處理人員解耦。PM就像一臺裝配器,安排具體人員處理具體的工作。
現在我們反過來理解IOC。字面意思:控制反轉
結合上面的例子:
- 控制: 選擇具體Dealer的控制權
- 反轉:指的是這種控制權轉移到PM手中。
對于軟件來說,即某一接口具體實現類的選擇控制權從調用類中移除,轉交由第三方決定, 即由Spring容器借由Bean配置來進行控制。
關于IoC的另外一個叫法,Martin Fowler提出了DI(Dependecy Injection 依賴注入),即讓調用類對你一個接口實現類的依賴關系由地方(容器或者協作類)注入,以移除調用類對某一個接口實現類的依賴。
很顯然, 依賴注入比控制反轉更加直接明了,易于理解。
IoC類型
從注入方法上看, IoC分為
Spring支持 構造函數注入和屬性注入。
構造函數注入
在構造函數注入中,通過調用類的構造函數,將接口實現類通過構造函數變量傳入
package com.xgj.master.ioc.consInj;import com.xgj.master.ioc.specific.DealerImpl;public class DoDistributedWork {private DealerImpl dealerImpl ;// 注入Dealer的實現類public DoDistributedWork(DealerImpl dealerImpl){this.dealerImpl = dealerImpl;}public void doSomething(){dealerImpl.doDevelopWork();} }DoDistributedWork 的構造函數不關心由誰來處理工作,只要在構造函數中傳入的處理者能夠完成指定工作即可, 具體的處理者由PM來安排,如下
package com.xgj.master.ioc.consInj;import com.xgj.master.ioc.specific.DealerImpl;public class PM {public void distribute() {// 指定Dealer的具體人員DealerImpl dealerImpl = new DealerImpl();// 注入dealerImpl到工作中DoDistributedWork distributedWork = new DoDistributedWork(dealerImpl);distributedWork.doSomething();}public static void main(String[] args) {PM pm = new PM();pm.distribute();}}屬性注入
有時候,并非每個場景都需要DealerImpl,在這種情況使用構造函數注入并不妥當 ,可以考慮使用屬性注入。
package com.xgj.master.ioc.properInj;import com.xgj.master.ioc.intf.Dealer;public class DoDistributedWork {private Dealer dealer ;// 屬性注入public void setDealer(Dealer dealer) {this.dealer = dealer;}public void doSomething(){dealer.doDevelopWork();} }為Dealer提供一個setter方法,以便PM在需要注入Dealer的具體實現類。
package com.xgj.master.ioc.properInj;import com.xgj.master.ioc.intf.Dealer; import com.xgj.master.ioc.specific.DealerImpl;public class PM {public void distribute(){Dealer dealer = new DealerImpl();DoDistributedWork distributedWork = new DoDistributedWork();//通過屬性setter方法 注入distributedWork.setDealer(dealer);distributedWork.doSomething();}public static void main(String[] args) {PM pm = new PM();pm.distribute();} }通過容器完成依賴關系的注入
雖然實現了 DoDistributedWork 和 DealerImpl的解耦,但是這些代碼仍然存在,只是轉移到了PM中而已。
如何將PM這部分也不要呢? 假設有個管理部門,管理部分來選擇PM、Dealer等等,那么 每個部分之間就都實現了解耦。我們可以更加專注于也位于邏輯的開發。
Spring就是這樣的一個容器,通過配置文件或者注解描述類和類之間的依賴關系,自動完成類的初始化和依賴注入工作。
package com.xgj.master.ioc.springInj;import com.xgj.master.ioc.intf.Dealer;public class DealerImpl implements Dealer{@Overridepublic void doDevelopWork() {System.out.println(DealerImpl.class.getSimpleName() +" says that he will do the work"); } } package com.xgj.master.ioc.springInj;public class DoDistributedWork {private DealerImpl dealerImpl ;public void setDealerImpl(DealerImpl dealerImpl) {this.dealerImpl = dealerImpl;}public void doSomething(){dealerImpl.doDevelopWork();} } <?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:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"><!-- 實現類實例化 --><bean id="dealerImpl" class="com.xgj.master.ioc.springInj.DealerImpl" /><bean id="doDistributedWork" class="com.xgj.master.ioc.springInj.DoDistributedWork"p:dealerImpl-ref="dealerImpl" /> <!-- 通過 dealerImpl-ref 建立依賴關系--> </beans>測試類
package com.xgj.master.ioc.springInj;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringInjTest {public static void main(String[] args) {// TODO Auto-generated method stubApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");DoDistributedWork doDistributedWork = (DoDistributedWork) context.getBean("doDistributedWork");doDistributedWork.doSomething();} }涉及的Java知識-Java反射
Spring為什么會這么簡潔,僅僅靠一個配置文件就可以實例化并裝配好程序用到的Bean呢?
主要歸功于Java類反射功能。
詳見 Java-Java反射
總結
以上是生活随笔為你收集整理的Spring-IoC容器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring-Spring MVC +
- 下一篇: Java-Java反射