自定义实现IOC思路拆解
近日在理解IOC与DI,看了很多概念,也写过很多小练习,但总觉得只是认识,不甚熟悉,蓦然回首,偶尔还能发出“大兄dei,您哪位?”的感慨。在前辈的指导下,自己写了个玩具性质的IOC容器,逐步的摸索过程让很多浮于水上的知识点瞬间有了一花一世界的立体感。特此记录,希望对你的学习也能有所帮助。
思路
- 明确IOC思想——明确需求,知道需要实现的初步效果
- 确定实现方式——拆解需求,逐功能点实现初步效果
- 设定完善点——发现并确立需要完善的关键问题
- 拆解并实现问题——解决问题
- 寻找参照,发现问题——头脑风暴,提升解决问题的能力
一、初步实现"IOC思想"
IOC(Inersion of Control):控制反转
借助于“第三方”实现具有依赖关系的对象之间的解耦
深度理解
软件系统没有引入IOC容器前(如图1):对象直接相互依赖,若对象A进行初始化,则必须主动去创建对象B或使用已创建的对象B,这个创建对象或者使用对象的过程,控制器在Coder手中。
软件系统引入IOC容器后(如图2):对象间失去直接联系,若对象A进行初始化,IoC容器会主动创建一个对象B注入到对象A需要的地方。
对象A获得依赖对象B的过程,由Coder的主动行为,变成了被动行为,控制权颠倒,即控制反转。
文字参考“浅谈IOC”,若是觉得还是很抽象,可参考原文
实现效果
通过对IOC思想的理解,我们可以得出,IOC容器需要实现关于对象的创建与存取功能。
我们应该实现以下3个接口:
/**
* 注册一个Class到IoC容器中
* @param clasz
* @throws Exception
*/
void registerBean(Class<?> clasz) throws Exception;
/**
* 初始化装配
*/
void initAutoWired();
/**
* 获取bean——根据Class获取Bean
* @param clasz
*/
<T> T getBean(Class<T> clasz);
创建对象
Constructor:构造方法
创建对象:
T newInstance(Object... initargs)
如果使用空参构造方法创建对象,操作可以简化:Class对象的newInstance()方法
String name = clasz.getName();
//创建对象
Constructor constructor = clasz.getConstructor();
Object obj = constructor.newInstance(null);
初始化装配
存储对象——创建一个Map容器,存储对象
//存储所有的对象(类名:该类的实例化对象)
private final Map<String ,Object> beanNameMap;
获取对象
通过类名,从Map容器中获取对象
啊。。。就这?
不,这只是开始
注意,我们的根本目的是学习和思考
?!
二、完善实现"IOC思想"
发现问题
1、我们通过类名实例化对象,那么类名从何而来?如何不通过Coder自动化获取类名? 2、我们仅仅创建对象,并不是完整的实例化对象,成员属性均未赋值,如何赋值?赋什么值? 3、若类之间存在聚合、组合等关系,那么如何实现注入?
解决问题
Q1——自动获取所有类名
思路拆解
我们可以扫描包下的所有类,找到需要实例化的实体类,获取他们的类名 关键点:
1.扫描存放实体类的包 2.筛选出需要实例化的实体类 3.获取实体类的类名,并存放至容器
关键点1有很多种方式实现,只是输出结果要成为关键点2的实现依据,
即,通过什么判断筛选实体类?——注解
实现步骤
确定了通过注解筛选实体类,那么对应着扫描实体包下该注解标注的实体类,获取类名,存放至容器
1.自定义注解类——标志这个类需要加入bean管理 2.通过反射扫描对应的包——导入reflections包 3.获取标注了刚刚自定义注解类的实体类
关于reflections包若是不太熟悉,可参考