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

如何讓組件再也不依賴容器?這篇java

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

 

服務定位器

 

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

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

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

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

 

[java] view plain copythis

  1. public class ServiceLocator {  
  2.       
  3.     static{  
  4.         //該類加載的時候執行一次  
  5.         Container.init();  
  6.     }  
  7.     public static Object getDao(){  
  8.         return Container.getComponent("dao4Mysql");  
  9. //      return Container.getComponent("dao4Oracle");  
  10.     }  
  11. }  

修改ServiceImpl的查找邏輯:spa

 

 

[java] view plain copy.net

  1. import com.tgb.container.ServiceLocator;  
  2. import com.tgb.container.dao.Dao;  
  3. import com.tgb.container.service.Service;  
  4.   
  5. public class ServiceImpl implements Service {  
  6.     // 從服務器定位器查找所需的接口  
  7.     private Dao dao = (Dao) ServiceLocator.getDao();;    
  8.       
  9.     @Override  
  10.     public void serviceMethod() {  
  11.         dao.daoMethod();  
  12.     }  
  13.   
  14. }  

UML類圖:設計

 

        

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

式」管理。

 

控制反轉(IoC)

 

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

調用類的對象中。

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

 

修改Service接口:

 

[java] view plain copy

  1. import com.tgb.container.dao.Dao;  
  2.   
  3.   
  4. public interface Service {  
  5.     //增長注入接口的方法  
  6.     public void setDao(Dao dao);  
  7.     public void serviceMethod();  
  8. }  

修改ServiceImpl:

 

 

[java] view plain copy

  1. import com.tgb.container.dao.Dao;  
  2. import com.tgb.container.service.Service;  
  3.   
  4. public class ServiceImpl implements Service {  
  5.     private Dao dao;    
  6.     //依賴注入  
  7.     public void setDao(Dao dao) {  
  8.         this.dao= dao;  
  9.     }  
  10.       
  11.     @Override  
  12.     public void serviceMethod() {  
  13.         dao.daoMethod();  
  14.     }  
  15. }  

修改Container類的初始化方法:

 

 

[java] view plain copy

  1. import java.util.HashMap;  
  2. import java.util.Map;  
  3.   
  4. import com.tgb.container.dao.Dao;  
  5. import com.tgb.container.dao.impl.Dao4MySqlImpl;  
  6. import com.tgb.container.service.Service;  
  7. import com.tgb.container.service.impl.ServiceImpl;  
  8.   
  9. public class Container {  
  10.     private static Map<String, Object> components;  
  11.   
  12.     private Container() {  
  13.     }  
  14.   
  15.     /** 
  16.      * 初始化容器 
  17.      */  
  18.     public static synchronized void init() {  
  19.         if (components == null) {  
  20.             components = new HashMap<String, Object>();  
  21.               
  22.             //寫一個讀配置文件的類,根據讀取的配置文件,反射對應的類  
  23.             //反射好類後進行 依賴管理,往對應的屬性上注入相應的類  
  24.               
  25.             Dao dao4Mysql = new Dao4MySqlImpl();  
  26.             components.put("dao4Mysql", dao4Mysql);  
  27.               
  28.             Service service = new ServiceImpl();    
  29.             components.put("service", service);  
  30.               
  31.             //容器維護依賴關係  
  32.             service.setDao(dao4Mysql);  
  33.         }  
  34.     }  
  35.   
  36.     /** 
  37.      * 查找組件 
  38.      *  
  39.      * @param id 
  40.      * @return 
  41.      */  
  42.     public static Object getComponent(String id) {  
  43.         return components.get(id);  
  44.     }  
  45. }  

UML類圖:

 

 

        

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

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

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

 

對比

 

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

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

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

相關文章
相關標籤/搜索