再上一篇文章中,楼主和大家一起分析spring的 IOC 实现,剖析了Spring的源码,看的出来,源码异常复杂,这是因为Spring的设计者需要考虑到框架的扩展性,健壮性,性能等待元素,因此设计的很复杂。楼主在最后也说要实现一个简单的 IOC,让我们更加深刻的理解IOC,因此,有了这篇文章。
当然我们是仿照Spring 的 IOC,因此代码命名和设计基本是仿照spring的。
我们将分为几步来编写简易 IOC,首先设计组件,再设计接口,然后关注实现。
1. 设计组件。
我们还记得Spring中最重要的有哪些组件吗?BeanFactory
容器,BeanDefinition
Bean的基本数据结构,当然还需要加载Bean的资源加载器
。大概最后最重要的就是这几个组件。容器用来存放初始化好的Bean,BeanDefinition 就是Bean的基本数据结构,比如Bean的名称,Bean的属性 PropertyValue
,Bean的方法,是否延迟加载,依赖关系等。资源加载器就简单了,就是一个读取XML配置文件的类,读取每个标签并解析。
2. 设计接口
首先肯定需要一个BeanFactory,就是Bean容器,容器接口至少有2个最简单的方法,一个是获取Bean,一个注册Bean.
/**
* 需要一个beanFactory 定义ioc 容器的一些行为 比如根据名称获取bean, 比如注册bean,参数为bean的名称,bean的定义
*
* @author stateis0
* @version 1.0.0
* @Date 2017/11/30
*/
public interface BeanFactory {
/**
* 根据bean的名称从容器中获取bean对象
*
* @param name bean 名称
* @return bean实例
* @throws Exception 异常
*/
Object getBean(String name) throws Exception;
/**
* 将bean注册到容器中
*
* @param name bean 名称
* @param bean bean实例
* @throws Exception 异常
*/
void registerBeanDefinition(String name, BeanDefinition bean) throws Exception;
}
根据Bean的名字获取Bean对象,注册参数有2个,一个是Bean的名字,一个是 BeanDefinition 对象。
定义完了Bean最基本的容器,还需要一个最简单 BeanDefinition 接口,我们为了方便,但因为我们这个不必考虑扩展,因此可以直接设计为类,BeanDefinition 需要哪些元素和方法呢? 需要一个 Bean 对象,一个Class对象,一个ClassName字符串,还需要一个元素集合 PropertyValues。这些就能组成一个最基本的 BeanDefinition 类了。那么需要哪些方法呢?其实就是这些属性的get set 方法。 我们看看该类的详细:
package cn.thinkinjava.myspring;
/**
* bean 的定义
*
* @author stateis0
*/
public class BeanDefinition {
/**
* bean
*/
private Object bean;
/**
* bean 的 CLass 对象
*/
private Class beanClass;
/**
* bean 的类全限定名称
*/
private String ClassName;
/**
* 类的属性集合
*/
private PropertyValues propertyValues = new PropertyValues();
/**
* 获取bean对象
*/
public Object getBean() {
return this.bean;
}
/**
* 设置bean的对象
*/
public void setBean(Object bean) {
this.bean = bean;
}
/**
* 获取bean的Class对象
*/
public Class getBeanclass() {
return this.beanClass;
}
/**
* 通过设置类名称反射生成Class对象
*/
public void setClassname(String name) {
this.ClassName = name;
try {
this.beanClass = Class.forName(name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取bean的属性集合
*/
public PropertyValues getPropertyValues() {
return this.propertyValues;
}
/**
* 设置bean的属性
*/
public void setPropertyValues(PropertyValues pv) {
this.propertyValues = pv;
}
}
有了基本的 BeanDefinition 数据结构,还需要一个从XML中读取并解析为 BeanDefinition 的操作类,首先我们定义一个 BeanDefinitionReader 接口,该接口只是一个标识,具体由抽象类去实现一个基本方法和定义一些基本属性,比如一个读取时需要存放的注册容器,还需要一个委托一个资源加载器 ResourceLoader, 用于加载X