开发IOC容器

来源:互联网 发布:梦幻西游高级宝石算法 编辑:程序博客网 时间:2024/06/13 10:33

什么是IoC(Inversion of Control)?什么是DI(Dependency Injection)?不多解释,自己Google!希望你先明确几个概念,该文章不做这方面的阐述,重点关注如何实现。我将用简要的语言从需求,设计,代码三方面来描述一个简单的IoC容器,来说明IoC容器是如何帮我们创建类的实例、如何实现依赖注入,最后会奉上一个完整的IoC容器实例。

       

一、需求,实现一个IoC容器


1、需求描述:



2、图中一些概念:


(1)服务元数据:一种是我们的编译好的类文件,即.class文件;另一种是xml文件。你可以理解为spring的注解和xml两种配置bean的方式。

(2)服务定义信息:由元数据转换来的信息,即读取bean中的注解或xml文件,获取到的对象描述信息。

(3)服务提供者:对象的实例。你可以理解为Spring中Bean的实例;

(4)服务定义信息存储区:保存服务定义信息的地方;

(5)服务提供者实例缓存区:保存服务提供者的地方。


3、流程描述:


(1)创建容器:初始化容器,实质是初始化容器内部的工厂,然后读取元数据,转化为服务定义信息,保存到服务定义信息存储区;

(2)调用服务提供者A的方法:获取该服务提供者A的服务定义信息,判断是否有缓存,如果有,直接调用缓存中的A;如果没有,据此实例化A,放入缓存,若发现A依赖其他服务提供者B,则查找缓存,如果有,将缓存中的B注入A;否则实例化B,注入到A中,同时放入缓存。以此类推。

(3)上面两个是核心流程,在此基础上,扩展了几个流程:

      1)获取所有服务提供者定义信息;

     2)获取所有服务提供者实例;

     3)获取某个服务提供者实例;

     4)热加载新的服务提供者。


二、设计,根据需求,以面向对象为基础,融合几种设计模式来勾勒IOC容器。

注:由于源码较多,会占很大篇幅,所以只给出了部分核心代码实现,所有代码见我的CSDN CODE,见文章末尾的说明。


1、UML,类图



2、设计说明


从类图可以看出,严格按照面向接口的方式编程,松耦合的设计保证了可扩展性和灵活性。

我定义了一套实现IOC容器的规范,这套规范的直接表现就是一组接口及其关系,有没有一点J2EE的感觉。然后,我给出了各个接口的一个默认实现,也就是给出了一个容器的默认实现。其他开发者既可以全部我的默认实现或全部使用自定义实现,也可以部分组件使用默认实现,部分组件实现自定义实现。


3、介绍接口与默认实现,即扩展点。


(1)Container接口及默认实现



核心代码:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import com.tgb.Entity.BeanEntity;  
  2. import com.tgb.data.IDataContext;  
  3.   
  4. /** 
  5.  * @Author : JiaLin 
  6.  * @Email : shan9liang@163.com 
  7.  * @Date : 2014/6/22 
  8.  * @Description :容器的核心接口 
  9.  */  
  10.   
  11. public interface IContainer{  
  12.   
  13.     //获取容器的某个服务提供者实例  
  14.     public Object getBean(String name);  
  15.   
  16.     //根据服务提供者名称,服务名称,参数来获取容器提供的服务  
  17.     //由三者确定一个唯一的服务。  
  18.     public Object getService(String beanName,String serviceName,Object... args);  
  19.   
  20.     //获取容器所有服务描述信息  
  21.     public IDataContext getBeanDefinitionContext();  
  22.   
  23.     //获取容器中某个服务提供者的描述信息  
  24.     public BeanEntity getBeanDefinition(String name);  
  25.   
  26.     //获取容器中所有服务提供者实例的缓存  
  27.     public IDataContext getBeanCacheContext();  
  28.   
  29.     //热加载新的服务提供者  
  30.     public void initContainerService(String resource);  
  31.   
  32. }  

说明:Container采用外观模式,充当Factory的外观层。Container可以自定义实现,这是扩展点一。而且使用了工厂模式和策略模式实现容器内部具体工厂的动态加载。


(2)Factory接口与默认实现


核心代码:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import com.tgb.Entity.BeanEntity;  
  2. import com.tgb.data.IDataContext;  
  3. import com.tgb.handler.HandlerDecorator;  
  4.   
  5. import java.io.Serializable;  
  6.   
  7. /** 
  8.  * @Author : JiaLin 
  9.  * @Email : shan9liang@163.com 
  10.  * @Date : 2014/6/22 
  11.  * @Description : 抽象的服务工厂,定义处理服务的算法骨架,具体由其子类实现。 
  12.  */  
  13.   
  14.   
  15. //使用模板方法模式定义算法的骨架,具体实现有相应的子类去做。  
  16. public abstract class AbstractBeanFactory implements IBeanFactory, Serializable {  
  17.   
  18.     //----------组件初始化----------begin-----  
  19.   
  20.     protected IDataContext beanDefinitionContext;//服务描述信息的存储区  
  21.     protected IDataContext beanCacheContext; //服务提供者实例的缓存区  
  22.     protected HandlerDecorator handlerDecorator;//转换器(元数据到服务描述信息)  
  23.   
  24.     //设置服务描述信息的存储区  
  25.     public abstract void setBeanDefinitionContext(String beanDefinitionContextName, String resource);  
  26.   
  27.     //设置服务提供者实例的缓存区  
  28.     public abstract void setBeanCacheContext(String beanCacheContextName);  
  29.   
  30.     //设置转换器(元数据到服务描述信息)  
  31.     public abstract void setHandler(String defaultHandler, String handlerName);  
  32.   
  33.     @Override  
  34.     //模板方法  
  35.     //注册服务组件,初始化服务描述信息  
  36.     public final void registerBeanDefinition(String resource, String cacheContext, String definitionContext, String defaultHandler, String customHandler) {  
  37.   
  38.         this.setHandler(defaultHandler, customHandler);  
  39.         this.setBeanCacheContext(cacheContext);  
  40.         this.setBeanDefinitionContext(definitionContext, resource);  
  41.     }  
  42.   
  43.     //----------组件初始化----------end-----  
  44.   
  45.   
  46.     //----------服务提供者的生命周期-----begin--------  
  47.   
  48.     //获取某个服务提供者的服务描述信息  
  49.     public abstract BeanEntity getBeanDefinition(String name);  
  50.   
  51.     //检查该服务提供者的实例是否有缓存  
  52.     public abstract boolean containsBeanCache(String name);  
  53.   
  54.     //从缓存中获取服务提供者的实例  
  55.     public abstract Object getBeanCache(String name);  
  56.   
  57.     //创建服务提供者  
  58.     public abstract Object creatBean(BeanEntity beanEntity);  
  59.   
  60.     //将服务提供者实例注册到缓存  
  61.     public abstract Object regiterBeanCache(String name, Object obj);  
  62.   
  63.     //----------服务提供者的生命周期-----end--------  
  64.   
  65.     @Override  
  66.     //模板方法  
  67.     //获取服务提供者实例  
  68.     public final Object getBean(String name) {  
  69.   
  70.         //获取某个Bean的定义  
  71.         BeanEntity beanEntity = getBeanDefinition(name);  
  72.   
  73.         //判断这个Bean是否已经加载到缓存,如果有,直接返回  
  74.         if (containsBeanCache(name)) {  
  75.             return getBeanCache(name);  
  76.         }  
  77.   
  78.         //创建bean的实例  
  79.         Object beanObject = this.creatBean(beanEntity);  
  80.   
  81.         //注册到缓存  
  82.         regiterBeanCache(name, beanObject);  
  83.   
  84.         //返回bean的实例  
  85.         return beanObject;  
  86.     }  
  87.   
  88.     //获取所有的服务描述信息  
  89.     public abstract IDataContext getBeanDefinitionContext();  
  90.   
  91.     //获取所有的服务实例缓存信息  
  92.     public abstract IDataContext getBeanCacheContext();  
  93.   
  94. }  

说明:AbstractBeanFactory采用模板方法模式,AbstractBeanFactory中定义了初始化服务定义信息和获取服务提供者实例两个模板方法,定义了算法的骨架。模板方法依赖的方法的实现交给子类去完成,这里交给DefaultBeanFactory完成。可以实现自己的BeanFactory,这是扩展点二。


(3)DataContext的接口及实现



   核心代码:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import java.util.Map;  
  2.   
  3. /** 
  4.  * @Author : JiaLin 
  5.  * @Email : shan9liang@163.com 
  6.  * @Date : 2014/6/22 
  7.  * @Description :抽象的数据存储接口 
  8.  */  
  9. public interface IDataContext {  
  10.   
  11.     public  void initData(Map<String,Object> map);  
  12.   
  13.     public void set(String name,Object obj);  
  14.   
  15.     public Object get(String name);  
  16.   
  17.     public Map<String,Object> getAll();  
  18. }  

说明:IDataContext定义了存储区域应该有的方法,两个实现,DefaultBeanDefinitionContext是服务提供者描述信息存储的默认实现;DefaultBeanCacheContext是服务提供者实例存储的默认实现。可以自定义存储区实现,这是扩展点三。


(4)Handler接口及实现



核心代码:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import java.util.Map;  
  2.   
  3. /** 
  4.  * @Author : JiaLin 
  5.  * @Email : shan9liang@163.com 
  6.  * @Date : 2014/6/23 
  7.  * @Description :  抽象的处理器装饰者 
  8.  */  
  9.   
  10. //使用装饰者模式,可以动态添加功能(这里是动态添加元数据处理器)  
  11. //例如要扩展Annotation就需要自己扩展处理器,或者扩展xml处理器等等  
  12. public abstract class HandlerDecorator implements IHandler{  
  13.   
  14.     protected IHandler handler;  
  15.   
  16.     public void setHandler(IHandler handler){  
  17.         this.handler=handler;  
  18.     }  
  19.   
  20.   
  21.     @Override  
  22.     public Map<String, Object> convert(String string) {  
  23.   
  24.         if(handler!=null)  
  25.         {  
  26.             return handler.convert(string);  
  27.         }  
  28.   
  29.         return null;  
  30.     }  
  31. }  

说明:这里采用了一个装饰者模式,默认提供了一个注解装饰者DefaultAnnotationHandler,来把元数据中注解信息转换为服务提供者定义信息。其他开发者可继承HandlerDecorator,来实现自己的装饰者,例如把xml信息转换为服务提供者定义信息的Xmlhandler。工厂会依次实现这些装饰者解析元数据。这是扩展点四。


(5)Annotation



核心代码:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import java.lang.annotation.ElementType;  
  2. import java.lang.annotation.Retention;  
  3. import java.lang.annotation.RetentionPolicy;  
  4. import java.lang.annotation.Target;  
  5.   
  6. /** 
  7.  * @Author : JiaLin 
  8.  * @Email : shan9liang@163.com 
  9.  * @Date : 2014/6/22 
  10.  * @Description :用来标注服务的提供者 
  11.  */  
  12.   
  13. @Retention(RetentionPolicy.RUNTIME)  
  14. @Target( {  
  15.         ElementType.FIELD,  
  16.         ElementType.TYPE  
  17. })  
  18. public @interface Bean {  
  19.     String name();  
  20. }  

说明:这里提供了三个注解来描述服务提供者的元数据,handler据此将元数据转换为服务提供者定义信息。其他开发者可扩展该Annotation,实现自己的Annotation,然后自定义解析的handler,重写factory的createBean方法即可。这是扩展点五。


(5)定义数据结构,存储服务定义信息



核心代码:
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import java.util.List;  
  2.   
  3. /** 
  4.  * @Author : JiaLin 
  5.  * @Email : shan9liang@163.com 
  6.  * @Date : 2014/6/22 
  7.  * @Description :服务提供者描述信息载体,其数据结构如下: 
  8.  * 
  9.  *                                       BeanEntity 
  10.  * 
  11.  *                     name               type                      List 
  12.  *                   @bean注解名          Bean类型              ServicEntity的arrayList 
  13.  *                                                     ServiceEntity…… 
  14.  * 
  15.  *                                                 name           value               List 
  16.  *                                              @Service注解名      方法名          ParamEntity的ArrayList 
  17.  *                                                                               ParamEntity…… 
  18.  *                                                                             name            value 
  19.  *                                                                           @param注解名       参数类型 
  20.  */  
  21.   
  22. public class BeanEntity {  
  23.     private String name;  //服务提供者名  
  24.     private String type;  //服务提供者实例的类型  
  25.     private Object value;  //服务提供者实例  
  26.     private List<ServiceEntity> serviceEntityList;   //服务提供者提供的所有服务  
  27.     public BeanEntity(){}  
  28.     public BeanEntity(String name,String type)  
  29.     {  
  30.         this.name=name;  
  31.         this.type=type;  
  32.     }  
  33.     //省略get,set方法  
  34.      
  35. }  

(6)反射Util


说明:这是java反射的工具类,封装了一些反射常用方法。


(7)热加载监听器


说明:这个监听器,将监听某个位置,如果加入新的服务提供者元数据,将被容器热加载。


三、所有代码


1、上面介绍了需求,设计,以及核心代码,如果依然不过瘾,那来看看全部代码吧。

我已将这个小项目开源,托管到CSDN CODE 公有项目,项目首页:

https://code.csdn.net/shan9liang/ioccontainer


2、大家可以帮着改进,也可以下载查看,还有很多改进的地方,最近工作繁忙,有空会持续更新,欢迎提出宝贵意见。

原文地址

0 0
原创粉丝点击