一步步重構容器實現Spring框架——從一個簡單的容器開始(八)

最近一直在和容器打交道,甚至前面的博文,咱們也介紹了Spring的IoC的原理以及源碼,可是回頭看看,duang~ duang~的,仍是深了,不夠通俗易懂,不夠深刻淺出。因爲以上緣由吧,從這篇博客開始,咱們從一個簡單的容器開始,一步步的重構,最後實現一個基本的Spring框架的雛形,爲了幫助咱們更加深刻的理解Spring的IoC的原理和源碼。java

 

容器

  

      相信你們對容器並不陌生,它是生活中很是常見的物品,容器用來包裝和裝載物品的貯存器(如箱、罐、壇等等),可是在編程中什麼容器呢?咱們先看一下百科的解釋:sql

---------------------------------------------------------------------------------------------------------------------------------------------------------編程

        容器能夠管理對象的生命週期、對象與對象之間的依賴關係,您可使用一個配置文件(一般是XML),在上面定義好對象的名稱、如何產生(Prototype 方式或Singleton 方式)、哪一個對象產生以後必須設定成爲某個對象的屬性等,在啓動容器以後,全部的對象均可以直接取用,不用編寫任何一行程序代碼來產生對象,或是創建對象與對象之間的依賴關係。框架

---------------------------------------------------------------------------------------------------------------------------------------------------------ide

       看見上面的解釋,第一感受就是什麼玩意?說白了,容器就是一個專門用來管理對象的模塊。它負責建立對象,管理對象的依賴關係,管理對象的生命週期等等,相似這樣的模塊就叫容器。spa

       運行在容器中的對象也稱爲組件,它們必須遵循容器定義的規範。.net

  

普通實現

  

       咱們理解了容器以後,下面咱們從一個簡單的實例開始。先看一下代碼:設計

Service層:component

 

[java] view plain copy對象

  1. public interface Service {  
  2.     public void serviceMethod();  
  3. }  

[java] view plain copy

  1. import com.tgb.container.dao.Dao;  
  2. import com.tgb.container.dao.impl.Dao4MySqlImpl;  
  3. import com.tgb.container.service.Service;  
  4.   
  5. public class ServiceImpl implements Service {  
  6.     //實例化Dao實現  
  7.     private Dao dao = new Dao4MySqlImpl();    
  8.   
  9.     @Override  
  10.     public void serviceMethod() {  
  11.         //調用Dao實現的方法  
  12.         dao.daoMethod();  
  13.     }  
  14. }  

Dao層:

 

 

[java] view plain copy

  1. public interface Dao {  
  2.     public void daoMethod();  
  3. }  

[java] view plain copy

  1. import com.tgb.container.dao.Dao;  
  2.   
  3. public class Dao4MySqlImpl implements Dao {  
  4.     public void daoMethod(){  
  5.         System.out.println("Dao4MySqlImpl.daoMethod()");  
  6.           
  7.     }  
  8. }  

 

 

[java] view plain copy

  1. import com.tgb.container.dao.Dao;  
  2.   
  3. public class Dao4OracleImpl implements Dao {  
  4.     public void daoMethod(){  
  5.         System.out.println("Dao4OracleImpl.daoMethod()");  
  6.           
  7.     }  
  8.           
  9. }  


客戶端:

 

 

[java] view plain copy

  1. import com.tgb.container.service.Service;  
  2. import com.tgb.container.service.impl.ServiceImpl;  
  3.   
  4. public class Client {  
  5.     public static void main(String[] args) {  
  6.         //實例化Service實現  
  7.         Service service = new ServiceImpl();  
  8.         //調用Service實現的方法  
  9.         service.serviceMethod();  
  10.     }  
  11. }  

 

  

這段代碼的運行結果,你們一眼就能看出來,以下:

  

      Dao4MySqlImpl.daoMethod()

  

UML類圖以下:

           

       從上圖咱們能夠發現,ServiceImpl不只依賴Dao層接口,並且還依賴Dao層實現,顯然違背了面向對象的基本設計原則,依賴倒轉原則:抽象不該該依賴細節,細節應該依賴與抽象,說白了,就是針對接口編程,不要對實現編程。

   

藉助容器

  

        下面咱們使用容器來將依賴實現的關係去掉。

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.     //定義一個map結構的對象  
  11.     private static Map<String, Object> components;  
  12.   
  13.     private Container() {  
  14.     }  
  15.   
  16.     /** 
  17.      * 初始化容器 
  18.      */  
  19.     public static synchronized void init() {  
  20.         if (components == null) {  
  21.             components = new HashMap<String, Object>();  
  22.             //寫一個讀配置文件的類,根據讀取的配置文件,反射對應的類  
  23.             //反射好類後進行 依賴管理,往對應的屬性上注入相應的類  
  24.             //客戶端建立新類的時候把容器建立好的類付給新類  
  25.               
  26.             Dao dao4Mysql = new Dao4MySqlImpl();  
  27.             components.put("dao4Mysql", dao4Mysql);  
  28.               
  29.             Service service = new ServiceImpl();    
  30.             components.put("service", service);  
  31.               
  32.         }  
  33.     }  
  34.   
  35.     /** 
  36.      * 查找組件 
  37.      *  
  38.      * @param id 
  39.      * @return 
  40.      */  
  41.     public static Object getComponent(String id) {  
  42.         return components.get(id);  
  43.     }  
  44.   
  45. }  

修改ServiceImpl類:

 

 

 

[java] view plain copy

  1. import com.tgb.container.Container;  
  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) Container.getComponent("dao4Mysql");    
  8.   
  9.     @Override  
  10.     public void serviceMethod() {  
  11.         dao.daoMethod();  
  12.     }  
  13. }  

 

客戶端:

 

[java] view plain copy

  1. import com.tgb.container.Container;  
  2. import com.tgb.container.service.Service;  
  3.   
  4. public class Client {  
  5.     public static void main(String[] args) {  
  6.         //容器初始化,這個能夠用filter完成,只需在整個項目中初始化一次  
  7.         Container.init();  
  8.           
  9.         //從容器中查找接口  
  10.         Service service =(Service)Container.getComponent("service");  
  11.         //調用Service實現的方法  
  12.         service.serviceMethod();  
  13.     }  
  14. }  

 

此時的UML類圖以下:

        
        對比兩張類圖,咱們能夠發現,容器給咱們帶來了優勢,同時也帶來了缺點。

優勢:

       此時的Service層再也不依賴Dao層實現,而把這種對實現的依賴交給了容器。

缺點:

        可是咱們卻發現,ServiceImpl依賴了Container容器類,使得組件不能脫離容器獨立存在,顯然,這是一種「侵入式」的管理。

相關文章
相關標籤/搜索