【SSH進階之路】一步步重構容器實現Spring框架——解決容器對組件的「侵入式」管理的兩種方案--主動查找和控制反轉(九)

目錄java

      【SSH進階之路】一步步重構容器實現Spring框架——從一個簡單的容器開始(八)
      【SSH進階之路】一步步重構容器實現Spring框架——解決容器對組件的「侵入式」管理的兩種方案--主動查找和控制反轉(九)
      【SSH進階之路】一步步重構容器實現Spring框架——配置文件+反射實現IoC容器(十)
      【SSH進階之路】一步步重構容器實現Spring框架——完全封裝,實現簡單靈活的Spring框架(十一)已更新
sql

  

       對於IOC的原理,咱們曾經寫過一篇博文,【SSH進階之路】Spring的IOC逐層深刻——爲何要使用IOC[實例講設計模式

解](二),對比學習能夠對同一個問題理解的更加深入。安全

       上篇博文【SSH進階之路】一步步重構容器實現Spring框架——從一個簡單的容器開始(八),咱們爲了去掉接口服務器

對具體實現的依賴關係,封裝了一個特別簡陋的容器,最後給你們拋出了一個問題:如何讓組件再也不依賴容器?這篇框架

博文主要是經過兩種解決方案來解決這個問題,最後對比各自的優缺點。ide


服務定位器


       解決方案之一就是使用服務定位器(Service Locator),咱們也能夠叫主動查找。服務定位器用來封裝複雜的查學習

找邏輯,同時對外開放簡單的查找方法,全部組件均可以將查找請求委派給服務定位器。this

       服務定位器但是一個簡單的類,也能夠是一種複雜的機制,如JNDI。不一樣的容器有着不一樣的查找機制。spa

下面是一個簡單的服務定位器:

public class ServiceLocator {
	
	static{
		//該類加載的時候執行一次
		Container.init();
	}
	public static Object getDao(){
		return Container.getComponent("dao4Mysql");
//		return Container.getComponent("dao4Oracle");
	}
}
修改ServiceImpl的查找邏輯:

import com.tgb.container.ServiceLocator;
import com.tgb.container.dao.Dao;
import com.tgb.container.service.Service;

public class ServiceImpl implements Service {
	// 從服務器定位器查找所需的接口
	private Dao dao = (Dao) ServiceLocator.getDao();;  
	
	@Override
	public void serviceMethod() {
		dao.daoMethod();
	}

}
UML類圖:

        

        原先由ServiceImpl到Container的依賴線上添加了ServiceLocator,組件再也不直接依賴於容器,實現了「非侵入

式」管理。


控制反轉(IoC)


       解決方案之二就是使用控制反轉,咱們將控制權交給容器,在運行期才由容器決定將具體的實現動態的「注入」到

調用類的對象中。

       Ioc是一種通用的設計原則,DI(依賴注入)則是具體的設計模式。依賴注入有三種方式,咱們使用的是Setter注入。


修改Service接口:

import com.tgb.container.dao.Dao;


public interface Service {
	//增長注入接口的方法
	public void setDao(Dao dao);
	public void serviceMethod();
}
修改ServiceImpl:

import com.tgb.container.dao.Dao;
import com.tgb.container.service.Service;

public class ServiceImpl implements Service {
	private Dao dao;  
	//依賴注入
	public void setDao(Dao dao) {
		this.dao= dao;
	}
	
	@Override
	public void serviceMethod() {
		dao.daoMethod();
	}
}
修改Container類的初始化方法:

import java.util.HashMap;
import java.util.Map;

import com.tgb.container.dao.Dao;
import com.tgb.container.dao.impl.Dao4MySqlImpl;
import com.tgb.container.service.Service;
import com.tgb.container.service.impl.ServiceImpl;

public class Container {
	private static Map<String, Object> components;

	private Container() {
	}

	/**
	 * 初始化容器
	 */
	public static synchronized void init() {
		if (components == null) {
			components = new HashMap<String, Object>();
			
			//寫一個讀配置文件的類,根據讀取的配置文件,反射對應的類
			//反射好類後進行 依賴管理,往對應的屬性上注入相應的類
			
			Dao dao4Mysql = new Dao4MySqlImpl();
			components.put("dao4Mysql", dao4Mysql);
			
			Service service = new ServiceImpl();  
			components.put("service", service);
			
			//容器維護依賴關係
			service.setDao(dao4Mysql);
		}
	}

	/**
	 * 查找組件
	 * 
	 * @param id
	 * @return
	 */
	public static Object getComponent(String id) {
		return components.get(id);
	}
}
UML類圖:

       

       由ServiceImpl到Container的依賴線能夠直接抹掉了!

       Setter注入易於使用,可是會有安全問題。第一次注入以後,有可能再一次調用setter方法,改變了原有的依賴。

這種對依賴的無心修改會帶來沒法預料的後果。因此須要有安全檢查機制。


對比


       解決組件再也不依賴容器,咱們使用了兩種方案:服務定位器和控制反轉。

       一、使用服務定位器查找組件,這是一種主動查找的行爲。這種查找有一個缺點:組件須要知道如何查找資源。組件和容器依賴變成了組件和服務定位器的依賴。

       二、而後,咱們使用了控制反轉,這是一種被動查找的行爲。容器主動將資源推送給組件,組件則以一種合適的方式來接受資源。反轉資源獲取方向,這就是大名鼎鼎的Ioc(控制反轉)。


       從類圖中咱們能夠發現,容器須要知道各個組件,容器和組件的耦合度仍是很高的,下篇博文【SSH進階之路】 

一步步重構容器實現Spring框架——配置文件+反射實現IoC容器(十),咱們利用配置文件+反射進一步下降耦合度。

  

      源碼下載

相關文章
相關標籤/搜索