前两天写简历。写了一句:精通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接口及实现

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2hhbjlsaWFuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">


核心代码:

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2hhbjlsaWFuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">


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

(7)热载入监听器

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

三、全部代码

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

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

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

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


自己动手开发IOC容器的更多相关文章

  1. TypeC一个微软开发的超简单.NET依赖注入/IoC容器

    控制反转(IoC,Inversion of Control)是由Martin Fowler总结出来的一种设计模式,用来减少代码间的耦合.一般而言,控制反转分为依赖注入(Dependency Injec ...

  2. 《精通Spring 4.X企业应用开发实战》读书笔记1-1(IoC容器和Bean)

    很长一段时间关注在Java Web开发的方向上,提及到Jave Web开发就绕不开Spring全家桶系列,使用面向百度,谷歌的编程方法能够完成大部分的工作.但是这种不系统的了解总觉得自己的知识有所欠缺 ...

  3. Java开发工程师(Web方向) - 04.Spring框架 - 第2章.IoC容器

    第2章.IoC容器 IoC容器概述 abstract: 介绍IoC和bean的用处和使用 IoC容器处于整个Spring框架中比较核心的位置:Core Container: Beans, Core, ...

  4. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(6):Spring IOC容器学习(概念、作用、Bean生命周期)

    一.IOC控制反转概念 控制反转(IOC)是一种通过描述(在Java中可以是XML或者是注解)并通过第三方去生产或获取特定对象的方式. 主动创建模式,责任在于开发者,而在被动模式下,责任归于Ioc容器 ...

  5. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring IoC容器BeanFactory和ApplicationContext

    IoC 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建.Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring ...

  6. 自己动手实现一个简单的 IOC容器

    控制反转,即Inversion of Control(IoC),是面向对象中的一种设计原则,可以用有效降低架构代码的耦合度,从对象调用者角度又叫做依赖注入,即Dependency Injection( ...

  7. spring-1-spring介绍和IOC容器开发

    一.介绍 1.版本 2.下载(jar包依赖) 下载 所以搜索:https://repo.spring.io/release/org/springframework/spring/ 文件分配 maven ...

  8. Spring IOC 容器源码分析系列文章导读

    1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...

  9. 深入理解DIP、IoC、DI以及IoC容器

    摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.DI以及Ioc容器等概念.通过本文我们将一起学 ...

随机推荐

  1. [thinkphp]查看thinkphp系统定义的常量值

    echo 'MEMORY_LIMIT_ON: ' . MEMORY_LIMIT_ON . '<br>'; echo 'THINK_PATH: ' . THINK_PATH . '<b ...

  2. Fiddler在fiddler option设置还是抓不了HTTPS包解决办法

    1:请在“运行”,即下面这个地方输入certmgr.msc并回车,打开证书管理. 打开后,请点击操作--查找证书,如下所示: 然后输入“fiddler”查找所有相关证书,如下所示: 可以看到,我们找到 ...

  3. [POI2007]Tourist Attractions

    题目大意: 给你一个$n(n\leq 2\times 10^4)$个点,$m(m\leq 2\times 10^5)$条边的带边权的连通图.其中有$k(k\leq 20)$个关键点.关键点之间有$g$ ...

  4. C语言基础之指针

    1.指针的定义 格式:变量类型 *变量名; 1: // 定义了一个指针变量p 2: // 指针变量只能存储地址 3: // 指针就一个作用:能够根据一个地址值,访问对应的存储空间 4: // 指针变量 ...

  5. 【Linux】CentOS7上安装搜狗输入法

    找到一篇资料,提供安装搜狗输入法的方法,在http://www.cnblogs.com/Yiutto/p/6204085.html[也是本文的参考原地址] 请大家自行下载fcitx.tar.gz 1. ...

  6. adb 设备不识别

    android真坑 有两台测试机 都能连能snapdragon profiling了 忽然 一台不能识别了 adb devices 就不存在 一台一直是好的 kill server start ser ...

  7. wsdl2java在mac中点配置

    1.打开终端,默认是用户目录,输入以下命令: ls -a 显示隐藏文件 2.打开.bash_profile,输入以下命令 open .bash_profile 配置JAVA_HOME,AXIS2_HO ...

  8. Unity3d / 3ds max 模型分享站点

    http://www.cgrealm.org/model/ 王国3D模型库 http://www.cgjoy.com/ 游戏特效论坛

  9. 浙大PAT考试1077~1080(2014上机复试题目)

    题目地址:点击打开链接 还是太弱. . 英文太差.,, 预计要等待被虐了.. 1077 找最长的公共后缀,暴力就能够写: #include<iostream> #include<cs ...

  10. Cygwin-安装和配置ssh服务

    Cygwin介绍: Cygwin是一个在windows平台上执行的类UNIX模拟环境.它对于学习UNIX/Linux操作环境,或者从UNIX到Windows的应用程序移植,或者进行某些特殊的开发工作, ...