zoukankan      html  css  js  c++  java
  • 自己动手开发IOC容器

    前两天写简历。写了一句:精通Spring IoC容器。怎么个精通法?还是自己动手写个IOC容器吧。


    什么是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接口及默认实现



    核心代码:

    import com.tgb.Entity.BeanEntity;
    import com.tgb.data.IDataContext;
    
    /**
     * @Author : JiaLin
     * @Email : shan9liang@163.com
     * @Date : 2014/6/22
     * @Description :容器的核心接口
     */
    
    public interface IContainer{
    
        //获取容器的某个服务提供者实例
        public Object getBean(String name);
    
        //依据服务提供者名称,服务名称,參数来获取容器提供的服务
        //由三者确定一个唯一的服务。

    public Object getService(String beanName,String serviceName,Object... args); //获取容器全部服务描写叙述信息 public IDataContext getBeanDefinitionContext(); //获取容器中某个服务提供者的描写叙述信息 public BeanEntity getBeanDefinition(String name); //获取容器中全部服务提供者实例的缓存 public IDataContext getBeanCacheContext(); //热载入新的服务提供者 public void initContainerService(String resource); }


    说明:Container採用外观模式。充当Factory的外观层。Container能够自己定义实现,这是扩展点一。

    并且使用了工厂模式和策略模式实现容器内部详细工厂的动态载入。


    (2)Factory接口与默认实现


    核心代码:

    import com.tgb.Entity.BeanEntity;
    import com.tgb.data.IDataContext;
    import com.tgb.handler.HandlerDecorator;
    
    import java.io.Serializable;
    
    /**
     * @Author : JiaLin
     * @Email : shan9liang@163.com
     * @Date : 2014/6/22
     * @Description : 抽象的服务工厂。定义处理服务的算法骨架,详细由其子类实现。
     */
    
    
    //使用模板方法模式定义算法的骨架。详细实现有对应的子类去做。
    public abstract class AbstractBeanFactory implements IBeanFactory, Serializable {
    
        //----------组件初始化----------begin-----
    
        protected IDataContext beanDefinitionContext;//服务描写叙述信息的存储区
        protected IDataContext beanCacheContext; //服务提供者实例的缓存区
        protected HandlerDecorator handlerDecorator;//转换器(元数据到服务描写叙述信息)
    
        //设置服务描写叙述信息的存储区
        public abstract void setBeanDefinitionContext(String beanDefinitionContextName, String resource);
    
        //设置服务提供者实例的缓存区
        public abstract void setBeanCacheContext(String beanCacheContextName);
    
        //设置转换器(元数据到服务描写叙述信息)
        public abstract void setHandler(String defaultHandler, String handlerName);
    
        @Override
        //模板方法
        //注冊服务组件。初始化服务描写叙述信息
        public final void registerBeanDefinition(String resource, String cacheContext, String definitionContext, String defaultHandler, String customHandler) {
    
            this.setHandler(defaultHandler, customHandler);
            this.setBeanCacheContext(cacheContext);
            this.setBeanDefinitionContext(definitionContext, resource);
        }
    
        //----------组件初始化----------end-----
    
    
        //----------服务提供者的生命周期-----begin--------
    
        //获取某个服务提供者的服务描写叙述信息
        public abstract BeanEntity getBeanDefinition(String name);
    
        //检查该服务提供者的实例是否有缓存
        public abstract boolean containsBeanCache(String name);
    
        //从缓存中获取服务提供者的实例
        public abstract Object getBeanCache(String name);
    
        //创建服务提供者
        public abstract Object creatBean(BeanEntity beanEntity);
    
        //将服务提供者实例注冊到缓存
        public abstract Object regiterBeanCache(String name, Object obj);
    
        //----------服务提供者的生命周期-----end--------
    
        @Override
        //模板方法
        //获取服务提供者实例
        public final Object getBean(String name) {
    
            //获取某个Bean的定义
            BeanEntity beanEntity = getBeanDefinition(name);
    
            //推断这个Bean是否已经载入到缓存,假设有,直接返回
            if (containsBeanCache(name)) {
                return getBeanCache(name);
            }
    
            //创建bean的实例
            Object beanObject = this.creatBean(beanEntity);
    
            //注冊到缓存
            regiterBeanCache(name, beanObject);
    
            //返回bean的实例
            return beanObject;
        }
    
        //获取全部的服务描写叙述信息
        public abstract IDataContext getBeanDefinitionContext();
    
        //获取全部的服务实例缓存信息
        public abstract IDataContext getBeanCacheContext();
    
    }

    说明:AbstractBeanFactory採用模板方法模式,AbstractBeanFactory中定义了初始化服务定义信息和获取服务提供者实例两个模板方法。定义了算法的骨架。

    模板方法依赖的方法的实现交给子类去完毕,这里交给DefaultBeanFactory完毕。

    能够实现自己的BeanFactory,这是扩展点二。


    (3)DataContext的接口及实现



       核心代码:

    import java.util.Map;
    
    /**
     * @Author : JiaLin
     * @Email : shan9liang@163.com
     * @Date : 2014/6/22
     * @Description :抽象的数据存储接口
     */
    public interface IDataContext {
    
        public  void initData(Map<String,Object> map);
    
        public void set(String name,Object obj);
    
        public Object get(String name);
    
        public Map<String,Object> getAll();
    }

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


    (4)Handler接口及实现



    核心代码:

    import java.util.Map;
    
    /**
     * @Author : JiaLin
     * @Email : shan9liang@163.com
     * @Date : 2014/6/23
     * @Description :  抽象的处理器装饰者
     */
    
    //使用装饰者模式,能够动态加入功能(这里是动态加入元数据处理器)
    //比如要扩展Annotation就须要自己扩展处理器,或者扩展xml处理器等等
    public abstract class HandlerDecorator implements IHandler{
    
        protected IHandler handler;
    
        public void setHandler(IHandler handler){
            this.handler=handler;
        }
    
    
        @Override
        public Map<String, Object> convert(String string) {
    
            if(handler!=null)
            {
                return handler.convert(string);
            }
    
            return null;
        }
    }
    

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


    (5)Annotation



    核心代码:

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @Author : JiaLin
     * @Email : shan9liang@163.com
     * @Date : 2014/6/22
     * @Description :用来标注服务的提供者
     */
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target( {
            ElementType.FIELD,
            ElementType.TYPE
    })
    public @interface Bean {
        String name();
    }

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


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



    核心代码:
    import java.util.List;
    
    /**
     * @Author : JiaLin
     * @Email : shan9liang@163.com
     * @Date : 2014/6/22
     * @Description :服务提供者描写叙述信息载体,其数据结构例如以下:
     *
     *                                       BeanEntity
     *
     *                     name               type                      List
     *                   @bean注解名          Bean类型              ServicEntity的arrayList
     *                                                     ServiceEntity……
     *
     *                                                 name           value               List
     *                                              @Service注解名      方法名          ParamEntity的ArrayList
     *                                                                               ParamEntity……
     *                                                                             name            value
     *                                                                           @param注解名       參数类型
     */
    
    public class BeanEntity {
        private String name;  //服务提供者名
        private String type;  //服务提供者实例的类型
        private Object value;  //服务提供者实例
        private List<ServiceEntity> serviceEntityList;   //服务提供者提供的全部服务
        public BeanEntity(){}
        public BeanEntity(String name,String type)
        {
            this.name=name;
            this.type=type;
        }
        //省略get,set方法
       
    }

    (6)反射Util


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


    (7)热载入监听器


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


    三、全部代码


    1、上面介绍了需求,设计,以及核心代码,假设依旧只是瘾,那来看看所有代码吧。

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

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


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





  • 相关阅读:
    关于session
    bootstrap的栅格系统
    js小知识点
    js获取div基础元素
    fixed固定元素
    定时器之延时触发鼠标悬浮事件
    Comparator分组测试
    List去重比较
    点击事件和双击事件
    开机自启动
  • 原文地址:https://www.cnblogs.com/jhcelue/p/6805845.html
Copyright © 2011-2022 走看看