一步步重构容器实现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容器类,使得组件不能脱离容器独立存在,显然,这是一种“侵入式”的管理。

相关文章
相关标签/搜索